| /*=============================================================================# |
| # Copyright (c) 2008, 2021 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.r.core.sourcemodel; |
| |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; |
| |
| import static org.eclipse.statet.r.core.rsource.ast.RAsts.toJavaBooleanValue; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.OperationCanceledException; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.lang.NonNull; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.internal.r.core.sourcemodel.BuildSourceFrame.ElementAccessList; |
| import org.eclipse.statet.internal.r.core.sourcemodel.RSourceElementByElementAccess.RClass; |
| import org.eclipse.statet.internal.r.core.sourcemodel.RSourceElementByElementAccess.RClassExt; |
| import org.eclipse.statet.internal.r.core.sourcemodel.RSourceElementByElementAccess.RMethod; |
| import org.eclipse.statet.internal.r.core.sourcemodel.RSourceElementByElementAccess.RPkgImport; |
| import org.eclipse.statet.internal.r.core.sourcemodel.RSourceElementByElementAccess.RSlot; |
| import org.eclipse.statet.ltk.ast.core.AstInfo; |
| import org.eclipse.statet.ltk.model.core.element.LtkModelElement; |
| import org.eclipse.statet.ltk.model.core.element.SourceStructElement; |
| import org.eclipse.statet.ltk.model.core.element.WorkspaceSourceUnit; |
| import org.eclipse.statet.r.core.model.ArgsBuilder; |
| import org.eclipse.statet.r.core.model.ArgsDefinition; |
| import org.eclipse.statet.r.core.model.RCoreFunctions; |
| import org.eclipse.statet.r.core.model.RElement; |
| import org.eclipse.statet.r.core.model.RElementAccess; |
| import org.eclipse.statet.r.core.model.RElementName; |
| import org.eclipse.statet.r.core.model.RFrame; |
| import org.eclipse.statet.r.core.model.RLangSourceElement; |
| import org.eclipse.statet.r.core.model.RSourceFrame; |
| import org.eclipse.statet.r.core.model.RSourceUnit; |
| import org.eclipse.statet.r.core.model.RSourceUnitModelInfo; |
| import org.eclipse.statet.r.core.rlang.RTerminal; |
| import org.eclipse.statet.r.core.rsource.RSourceConstants; |
| import org.eclipse.statet.r.core.rsource.ast.Arithmetic; |
| import org.eclipse.statet.r.core.rsource.ast.Assignment; |
| import org.eclipse.statet.r.core.rsource.ast.CForLoop; |
| import org.eclipse.statet.r.core.rsource.ast.CIfElse; |
| import org.eclipse.statet.r.core.rsource.ast.CLoopCommand; |
| import org.eclipse.statet.r.core.rsource.ast.CRepeatLoop; |
| import org.eclipse.statet.r.core.rsource.ast.CWhileLoop; |
| import org.eclipse.statet.r.core.rsource.ast.DocuTag; |
| import org.eclipse.statet.r.core.rsource.ast.Dummy; |
| import org.eclipse.statet.r.core.rsource.ast.FCall; |
| import org.eclipse.statet.r.core.rsource.ast.FDef; |
| import org.eclipse.statet.r.core.rsource.ast.Help; |
| import org.eclipse.statet.r.core.rsource.ast.Logical; |
| import org.eclipse.statet.r.core.rsource.ast.Model; |
| import org.eclipse.statet.r.core.rsource.ast.NSGet; |
| import org.eclipse.statet.r.core.rsource.ast.NodeType; |
| import org.eclipse.statet.r.core.rsource.ast.NullConst; |
| import org.eclipse.statet.r.core.rsource.ast.NumberConst; |
| import org.eclipse.statet.r.core.rsource.ast.Power; |
| import org.eclipse.statet.r.core.rsource.ast.RAstNode; |
| import org.eclipse.statet.r.core.rsource.ast.RAstVisitor; |
| import org.eclipse.statet.r.core.rsource.ast.RAsts; |
| import org.eclipse.statet.r.core.rsource.ast.RAsts.FCallArgMatch; |
| import org.eclipse.statet.r.core.rsource.ast.Relational; |
| import org.eclipse.statet.r.core.rsource.ast.Seq; |
| import org.eclipse.statet.r.core.rsource.ast.Sign; |
| import org.eclipse.statet.r.core.rsource.ast.SourceComponent; |
| import org.eclipse.statet.r.core.rsource.ast.Special; |
| import org.eclipse.statet.r.core.rsource.ast.StringConst; |
| import org.eclipse.statet.r.core.rsource.ast.SubIndexed; |
| import org.eclipse.statet.r.core.rsource.ast.SubNamed; |
| import org.eclipse.statet.r.core.rsource.ast.Symbol; |
| |
| |
| /** |
| * Walks through the AST, analyzes element access, ... |
| * |
| * Saves the information in {@link RSourceUnitModelInfo} |
| */ |
| @NonNullByDefault |
| public class SourceAnalyzer extends RAstVisitor { |
| |
| |
| private static final int S_GLOBAL= 0; |
| private static final int S_LOCAL= 1; |
| private static final int S_SEARCH= 2; |
| |
| private static final int RETURN_SOURCE_CONTAINTER= 1; |
| private static final int RETURN_METHOD_SIGNATURE= 2; |
| private static final int RETURN_STRING_ARRAY= 3; |
| private static final int REG_CLASS_REPRESENTATION= 4; |
| private static final int REG_CLASS_PROTOTYPE= 5; |
| |
| private static final int[] NO_REQUESTS= { }; |
| private static final int[] STRING_ARRAY_REQUEST= { |
| RETURN_STRING_ARRAY }; |
| private static final int[] SIGNATURE_REQUESTS= { |
| RETURN_METHOD_SIGNATURE, RETURN_STRING_ARRAY }; |
| private static final int[] REPRESENTATION_REQUEST= { |
| REG_CLASS_REPRESENTATION }; |
| private static final int[] PROTOTYPE_REQUEST= { |
| REG_CLASS_PROTOTYPE }; |
| |
| private static final Integer FIRST= Integer.valueOf(0); |
| |
| |
| @SuppressWarnings("rawtypes") |
| private static final Comparator<SourceStructElement> SOURCEELEMENT_SORTER= new Comparator<SourceStructElement>() { |
| @Override |
| public int compare(final SourceStructElement e1, final SourceStructElement e2) { |
| return e1.getSourceRange().getStartOffset() - e2.getSourceRange().getStartOffset(); |
| } |
| }; |
| |
| |
| private static class ReturnValue { |
| |
| final int returnType; |
| |
| ReturnValue(final int returnType) { |
| this.returnType= returnType; |
| } |
| } |
| |
| private static class NodeArray extends ReturnValue { |
| |
| final RAstNode[] array; |
| |
| NodeArray(final int returnType, final RAstNode[] array) { |
| super(returnType); |
| this.array= array; |
| } |
| } |
| |
| |
| private static class SourceElementBuilder extends ReturnValue { |
| |
| |
| private final @Nullable SourceElementBuilder parent; |
| private final BuildSourceFrameElement element; |
| private final List<RSourceElementByElementAccess> children; |
| |
| private final List<ElementAccess> toCheck; |
| private final BuildSourceFrame envir; |
| |
| |
| SourceElementBuilder(final BuildSourceFrameElement element, |
| final @Nullable SourceElementBuilder parent, final BuildSourceFrame envir) { |
| super(RETURN_SOURCE_CONTAINTER); |
| this.element= element; |
| this.parent= parent; |
| this.children= new ArrayList<>(); |
| this.toCheck= new ArrayList<>(); |
| this.envir= envir; |
| } |
| |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb= new StringBuilder("SourceAnalyzer$SourceElementBuilder"); //$NON-NLS-1$ |
| sb.append("\n\tfor= ").append(this.element); //$NON-NLS-1$ |
| sb.append("\n\tin= ").append(this.envir); //$NON-NLS-1$ |
| |
| return sb.toString(); |
| } |
| |
| } |
| |
| private static class Signature extends ReturnValue { |
| |
| /** the access objects are not yet registered */ |
| private final @Nullable ElementAccess @Nullable [] argNameAccesses; |
| private final @Nullable String[] classNames; |
| |
| Signature(final @Nullable ElementAccess @Nullable [] argNameAccess, final @Nullable String[] classNames) { |
| super(RETURN_METHOD_SIGNATURE); |
| this.argNameAccesses= argNameAccess; |
| this.classNames= classNames; |
| } |
| |
| } |
| |
| private class RoxygenAdapter implements RoxygenAnalyzeContext { |
| |
| |
| private RSourceUnitModelInfoImpl modelInfo; |
| private int counter; |
| |
| |
| @Override |
| public RSourceUnitModelInfo getModelInfo() { |
| return this.modelInfo; |
| } |
| |
| @Override |
| public void createSelfAccess(final DocuTag docuTag, |
| final RLangSourceElement element, final RAstNode symbol) { |
| final String text= symbol.getText(); |
| if (text == null) { |
| return; |
| } |
| final RElementAccess elementAccess= ((RSourceElementByElementAccess)element).getAccess(); |
| if (elementAccess != null |
| && text.equals(elementAccess.getSegmentName()) |
| && elementAccess.getNextSegment() == null ) { |
| final ElementAccess access= new ElementAccess.Default(docuTag, symbol); |
| ((ElementAccess) elementAccess).shared.postAdd(access); |
| return; |
| } |
| } |
| |
| @Override |
| public void createNamespaceImportAccess(final DocuTag docuTag, |
| final RAstNode symbol) { |
| final String text= symbol.getText(); |
| if (text == null) { |
| return; |
| } |
| final ElementAccess access= new ElementAccess.Namespace(docuTag, symbol); |
| access.flags |= ElementAccess.A_IMPORT; |
| this.modelInfo.packageRefs.add(text, access); |
| } |
| |
| @Override |
| public void createNamespaceObjectImportAccess(final DocuTag docuTag, |
| final RSourceFrame namespace, final RAstNode symbol) { |
| final String text= symbol.getText(); |
| if (text == null) { |
| return; |
| } |
| if (namespace instanceof BuildSourceFrame) { |
| final ElementAccess access= new ElementAccess.Default(docuTag, symbol); |
| |
| final BuildSourceFrame namespaceFrame= (BuildSourceFrame) namespace; |
| final ElementAccessList namespaceList= namespaceFrame.data.get(text); |
| |
| final BuildSourceFrame next= this.modelInfo.localFrames.values().iterator().next(); |
| final ElementAccessList defaultList= next.data.get(text); |
| if (defaultList != null && defaultList.isCreated < BuildSourceFrame.CREATED_RESOLVED) { |
| next.data.remove(text); |
| if (namespaceList != null) { |
| namespaceList.entries.addAll(defaultList.entries); |
| for (final ElementAccess defaultAccess : defaultList.entries) { |
| defaultAccess.shared= namespaceList; |
| } |
| namespaceList.postAdd(access); |
| } |
| else { |
| defaultList.frame= namespaceFrame; |
| defaultList.postAdd(access); |
| namespaceFrame.data.put(text, defaultList); |
| } |
| } |
| else { |
| if (namespaceList != null) { |
| namespaceList.postAdd(access); |
| } |
| else { |
| final ElementAccessList accessList= new BuildSourceFrame.ElementAccessList(text); |
| accessList.frame= namespaceFrame; |
| accessList.postAdd(access); |
| namespaceFrame.data.put(text, accessList); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public @Nullable RSourceFrame getNamespaceFrame(final String name) { |
| final String id= BuildSourceFrame.createId(RFrame.PACKAGE, name, -1); |
| BuildSourceFrame frame= this.modelInfo.namespaceFrames.get(id); |
| if (frame == null) { |
| frame= new BuildSourceFrame.DefScope(RFrame.PACKAGE, id, name, null); |
| this.modelInfo.namespaceFrames.put(id, frame); |
| return frame; |
| } |
| return null; |
| } |
| |
| @Override |
| public void createSlotAccess(final DocuTag docuTag, |
| final RClass rClass, final RAstNode symbol) { |
| final String text= symbol.getText(); |
| if (text == null) { |
| return; |
| } |
| final ElementAccessList accessList= rClass.getBuildFrame().data.get(text); |
| if (accessList == null) { |
| return; |
| } |
| final List<? extends RLangSourceElement> children= rClass.getSourceChildren(null); |
| for (final RLangSourceElement child : children) { |
| if (child.getElementType() == RElement.R_S4SLOT |
| && text.equals(child.getElementName().getSegmentName())) { |
| final ElementAccess access= new ElementAccess.Slot(docuTag, symbol); |
| accessList.postAdd(access); |
| return; |
| } |
| } |
| } |
| |
| @Override |
| public void createArgAccess(final DocuTag docuTag, |
| final RMethod rMethod, final RAstNode symbol) { |
| final String text= symbol.getText(); |
| if (text == null) { |
| return; |
| } |
| final ElementAccessList accessList= rMethod.getBuildFrame().data.get(text); |
| if (accessList == null) { |
| return; |
| } |
| final List<? extends RLangSourceElement> children= rMethod.getSourceChildren(null); |
| for (final RLangSourceElement child : children) { |
| if (child.getElementType() == RElement.R_ARGUMENT |
| && text.equals(child.getElementName().getSegmentName())) { |
| final ElementAccess access= new ElementAccess.Default(docuTag, symbol); |
| access.flags |= ElementAccess.A_ARG; |
| accessList.postAdd(access); |
| return; |
| } |
| } |
| } |
| |
| @Override |
| public void createRSourceRegion(final RAstNode node) { |
| if (!SourceAnalyzer.this.roxygenExamples) { |
| this.counter= 0; |
| cleanup(); |
| init(); |
| SourceAnalyzer.this.roxygenExamples= true; |
| } |
| try { |
| final RoxygenRCodeElement element= new RoxygenRCodeElement(this.modelInfo.getSourceElement(), |
| this.counter++, SourceAnalyzer.this.topLevelEnvir, node ); |
| enterElement(element, SourceAnalyzer.this.topLevelEnvir, node); |
| node.acceptInRChildren(SourceAnalyzer.this); |
| leaveElement(); |
| } |
| catch (final InvocationTargetException unused) {} |
| } |
| |
| public void update(final RSourceUnitModelInfoImpl modelInfo) { |
| this.modelInfo= modelInfo; |
| SourceAnalyzer.this.roxygenAnalyzer.updateModel(SourceAnalyzer.this.roxygenAdapter); |
| } |
| |
| } |
| |
| |
| private RSourceUnit sourceUnit; |
| private List<EmbeddedRBuildElement> chunkElements; |
| private List<EmbeddedRBuildElement> inlineElements; |
| private AstInfo ast; |
| |
| private int anonymCount; |
| private final ArrayList<String> idComponents= new ArrayList<>(32); |
| private LinkedHashMap<String, BuildSourceFrame> frames; |
| private Map<String, BuildSourceFrame> dependencyEnvironments; |
| private final ArrayList<BuildSourceFrame> currentEnvironments= new ArrayList<>(32); |
| private BuildSourceFrame globalEnvir; |
| private BuildSourceFrame genericDefaultEnvir; |
| private BuildSourceFrame topLevelEnvir; |
| private BuildSourceFrame topScope; |
| private BasicPackageReferences packageRefs; |
| |
| private final LinkedList<RAstNode> argValueToIgnore= new LinkedList<>(); |
| private int[] request= NO_REQUESTS; |
| private @Nullable Object returnValue; |
| |
| private final ArrayList<SourceElementBuilder> sourceContainerBuilders= new ArrayList<>(); |
| private SourceElementBuilder currentSourceContainerBuilder; |
| |
| private RCoreFunctions configuredRDef; |
| private final Map<String, FCallAnalyzer> fCallAnalyzers= new HashMap<>(); |
| private FCallAnalyzer fCallFallback; |
| private final FCallAnalyzer fCallNoAnalysis= new FCallAnalyzer() { |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| }; |
| |
| private final RoxygenAnalyzer roxygenAnalyzer; |
| private final RoxygenAdapter roxygenAdapter; |
| private boolean roxygenExamples; |
| |
| private final HashMap<String, Integer> commonNames= new HashMap<>(); |
| private final HashMap<String, Integer> classNames= new HashMap<>(); |
| private final HashMap<String, Integer> importNames= new HashMap<>(); |
| |
| |
| public SourceAnalyzer() { |
| configure(RCoreFunctions.DEFAULT); |
| this.roxygenAnalyzer= new RoxygenAnalyzer(); |
| this.roxygenAdapter= new RoxygenAdapter(); |
| } |
| |
| public void configure(final RCoreFunctions rdef) { |
| this.configuredRDef= rdef; |
| this.fCallAnalyzers.clear(); |
| FCallAnalyzer analyzer; |
| |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_ASSIGN_NAME, new BaseAssign(rdef)); |
| analyzer= new BaseRemove(rdef); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_REMOVE_NAME, analyzer); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_REMOVE_ALIAS_RM, analyzer); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_EXISTS_NAME, |
| new BaseExists(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_GET_NAME, |
| new BaseGet(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_SAVE_NAME, |
| new BaseSave(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_CALL_NAME, |
| new BaseCall(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_DOCALL_NAME, |
| new BaseDoCall(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_LIBRARY_NAME, |
| new BaseLibrary(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_REQUIRE_NAME, |
| new BaseRequire(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_GLOBALENV_NAME, |
| new BaseGlobalenv(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_TOPENV_NAME, |
| new BaseTopenv(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.BASE_C_NAME, |
| new BaseC(rdef)); |
| |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETGENERIC_NAME, |
| new MethodsSetGeneric(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETGROUPGENERIC_NAME, |
| new MethodsSetGroupGeneric(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_REMOVEGENERIC_NAME, |
| new MethodsRemoveGeneric(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SIGNATURE_NAME, |
| new MethodsSignature(rdef)); |
| |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETCLASS_NAME, |
| new MethodsSetClass(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETCLASSUNION_NAME, |
| new MethodsSetClassUnion(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_REPRESENTATION_NAME, |
| new MethodsRepresentation(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_PROTOTYPE_NAME, |
| new MethodsPrototype(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETIS_NAME, |
| new MethodsSetIs(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_REMOVECLASS_NAME, |
| new MethodsRemoveClass(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_RESETCLASS_NAME, |
| this.fCallNoAnalysis); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETAS_NAME, |
| new MethodsSetAs(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETVALIDITY_NAME, |
| new MethodsSetValidity(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_GETCLASS_NAME, |
| new MethodsGetClass(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_GETCLASSDEF_NAME, |
| new MethodsGetClassDef(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_FINDCLASS_NAME, |
| new MethodsFindClass(rdef)); |
| |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_NEW_NAME, |
| new MethodsNew(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_AS_NAME, |
| new MethodsAs(rdef)); |
| |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SETMETHOD_NAME, |
| new MethodsSetMethod(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_REMOVEMETHOD_NAME, |
| new MethodsRemoveMethod(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_REMOVEMETHODS_NAME, |
| new MethodsRemoveMethods(rdef)); |
| |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_GETMETHOD_NAME, |
| new MethodsGetMethod(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SELECTMETHOD_NAME, |
| new MethodsSelectMethod(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_GETMETHODS_NAME, |
| new MethodsGetMethods(rdef)); |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_FINDMETHOD_NAME, |
| new MethodsFindMethod(rdef)); |
| |
| this.fCallAnalyzers.put(RCoreFunctions.METHODS_SLOT_NAME, |
| new MethodsSlot(rdef)); |
| |
| for (final String name : rdef.getKnownFunctions()) { |
| if (!this.fCallAnalyzers.containsKey(name)) { |
| this.fCallAnalyzers.put(name, new CommonDefBased(rdef.getArgs(name))); |
| } |
| } |
| |
| // DEBUG |
| // final Set<String> test= new HashSet<String>(); |
| // test.addAll(rdef.getKnownFunctions()); |
| // test.removeAll(fFCallAnalyzers.keySet()); |
| // System.out.println("nonregistered RCoreFunctions: " + test.toString()); |
| |
| this.fCallFallback= new NoDefFallback(); |
| } |
| |
| |
| public @Nullable RSourceUnitModelInfo createModel(final RSourceUnit u, final AstInfo sourceComponent) { |
| if (!(sourceComponent.getRoot() instanceof SourceComponent)) { |
| throw new IllegalArgumentException("ast"); //$NON-NLS-1$ |
| } |
| final SourceComponent root= (SourceComponent)sourceComponent.getRoot(); |
| this.anonymCount= 0; |
| this.sourceUnit= u; |
| |
| try { |
| init(); |
| |
| final RSourceUnitElement fileElement= new RSourceUnitElement(this.sourceUnit, this.topLevelEnvir, root); |
| enterElement(fileElement, this.topLevelEnvir, root); |
| root.acceptInRChildren(this); |
| leaveElement(); |
| |
| finish(); |
| this.ast= new AstInfo(AstInfo.LEVEL_MODEL_DEFAULT, sourceComponent); |
| final RSourceUnitModelInfoImpl modelInfo= new RSourceUnitModelInfoImpl(this.ast, this.frames, this.topLevelEnvir, |
| this.packageRefs, this.dependencyEnvironments, fileElement ); |
| |
| this.roxygenExamples= false; |
| this.roxygenAdapter.update(modelInfo); |
| if (this.roxygenExamples) { |
| finish(); |
| for (final Iterator<Map.Entry<@Nullable String, ElementAccessList>> iter= this.topLevelEnvir.data.entrySet().iterator(); iter.hasNext(); ) { |
| final Map.Entry<@Nullable String, ElementAccessList> entry= iter.next(); |
| final String name= entry.getKey(); |
| final ElementAccessList docuList= entry.getValue(); |
| if (docuList.isCreated == BuildSourceFrame.CREATED_NO) { |
| iter.remove(); |
| final ElementAccessList modelList= modelInfo.topFrame.data.get(name); |
| if (modelList != null) { |
| for (final ElementAccess access : docuList.entries) { |
| access.shared= modelList; |
| } |
| modelList.entries.addAll(docuList.entries); |
| } |
| else { |
| docuList.frame= modelInfo.topFrame; |
| modelInfo.topFrame.data.put(name, docuList); |
| } |
| } |
| } |
| for (final Iterator<Map.Entry<String, ElementAccessList>> iter= this.packageRefs.data.entrySet().iterator(); iter.hasNext(); ) { |
| final Map.Entry<String, ElementAccessList> entry= iter.next(); |
| final String name= entry.getKey(); |
| final ElementAccessList docuList= entry.getValue(); |
| if (docuList.isCreated == BuildSourceFrame.CREATED_NO) { |
| iter.remove(); |
| final ElementAccessList modelList= modelInfo.packageRefs.data.get(name); |
| if (modelList != null) { |
| for (final ElementAccess access : docuList.entries) { |
| access.shared= modelList; |
| } |
| modelList.entries.addAll(docuList.entries); |
| } |
| else { |
| docuList.frame= modelInfo.topFrame; |
| modelInfo.packageRefs.data.put(name, docuList); |
| } |
| } |
| } |
| } |
| |
| return modelInfo; |
| } |
| catch (final OperationCanceledException e) {} |
| catch (final InvocationTargetException e) {} |
| finally { |
| cleanup(); |
| this.sourceUnit= null; |
| } |
| return null; |
| } |
| |
| |
| public void beginChunkSession(final RSourceUnit su, final AstInfo ast) { |
| this.anonymCount= 0; |
| this.sourceUnit= su; |
| this.ast= ast; |
| if (this.chunkElements == null) { |
| this.chunkElements= new ArrayList<>(); |
| this.inlineElements= new ArrayList<>(); |
| } |
| |
| init(); |
| } |
| |
| public void processChunk(final EmbeddedRBuildElement element, final List<SourceComponent> sourceComponents) { |
| try { |
| this.chunkElements.add(element); |
| for (final SourceComponent sourceComponent : sourceComponents) { |
| element.envir= this.topLevelEnvir; |
| enterElement(element, this.topLevelEnvir, sourceComponent); |
| sourceComponent.acceptInRChildren(this); |
| leaveElement(); |
| } |
| } |
| catch (final OperationCanceledException e) {} |
| catch (final InvocationTargetException e) {} |
| } |
| |
| public void processInlineNode(final EmbeddedRBuildElement element, final SourceComponent sourceComponent) { |
| try { |
| this.inlineElements.add(element); |
| element.envir= this.topLevelEnvir; |
| enterElement(element, this.topLevelEnvir, sourceComponent); |
| sourceComponent.acceptInRChildren(this); |
| leaveElement(); |
| } |
| catch (final OperationCanceledException e) {} |
| catch (final InvocationTargetException e) {} |
| } |
| |
| public RSourceUnitModelInfo stopChunkSession() { |
| try { |
| finish(); |
| |
| final RSourceUnitModelInfoImpl modelInfo= new RSourceUnitModelInfoImpl(this.ast, this.frames, |
| this.topLevelEnvir, this.packageRefs, this.dependencyEnvironments, |
| new CompositeSourceElement(this.sourceUnit, this.topLevelEnvir, |
| this.chunkElements, this.ast.getRoot() )); |
| return modelInfo; |
| } |
| finally { |
| cleanup(); |
| this.sourceUnit= null; |
| this.chunkElements.clear(); |
| } |
| } |
| |
| |
| private void init() { |
| this.frames= new LinkedHashMap<>(); |
| this.dependencyEnvironments= new HashMap<>(); |
| final String projId= (this.sourceUnit instanceof WorkspaceSourceUnit) ? |
| ((WorkspaceSourceUnit)this.sourceUnit).getResource().getProject().getName() : |
| "<noproject:" + this.sourceUnit.getElementName(); //$NON-NLS-1$ |
| |
| final BuildSourceFrame fileEnvir= new BuildSourceFrame.DefScope(RFrame.PROJECT, |
| BuildSourceFrame.createId(RFrame.PROJECT, projId, 0), null, |
| new @NonNull BuildSourceFrame[0] ); // ref projects |
| |
| this.currentEnvironments.add(fileEnvir); |
| this.genericDefaultEnvir= this.topLevelEnvir= this.globalEnvir= fileEnvir; |
| this.packageRefs= new BasicPackageReferences(); |
| this.topScope= this.currentEnvironments.get(this.currentEnvironments.size() - 1); |
| |
| this.idComponents.add(projId); |
| } |
| |
| private void finish() { |
| for (final BuildSourceFrame si : this.dependencyEnvironments.values()) { |
| si.runLateResolve(false); |
| } |
| this.topLevelEnvir.parents= ImCollections.concatList(this.dependencyEnvironments.values(), this.topLevelEnvir.parents); |
| for (final BuildSourceFrame si : this.frames.values()) { |
| si.runLateResolve(false); |
| } |
| |
| final HashMap<String, Integer> commonNames= this.commonNames; |
| final HashMap<String, Integer> classNames= this.classNames; |
| final HashMap<String, Integer> importNames= this.importNames; |
| int anonymous= 0; |
| try { |
| for (final SourceElementBuilder seb : this.sourceContainerBuilders) { |
| if (seb.element.getElementName() == null |
| && seb.element instanceof RSourceElementByElementAccess.RMethod) { |
| final RSourceElementByElementAccess.RMethod element= (RSourceElementByElementAccess.RMethod)seb.element; |
| element.occurrenceCount= anonymous++; |
| registerAnonFunctionElement(element, seb.envir); |
| } |
| for (final RSourceElementByElementAccess element : seb.children) { |
| final String name= element.getElementName().getDisplayName(); |
| final HashMap<String, Integer> names; |
| switch (element.type & LtkModelElement.MASK_C1) { |
| case LtkModelElement.C1_CLASS: |
| names= classNames; |
| break; |
| case LtkModelElement.C1_IMPORT: |
| names= importNames; |
| break; |
| default: |
| names= commonNames; |
| break; |
| } |
| final Integer occ= names.get(name); |
| if (occ == null) { |
| names.put(name, FIRST); |
| } |
| else { |
| names.put(name, Integer.valueOf( |
| (element.occurrenceCount= occ + 1) )); |
| } |
| } |
| for (final ElementAccess access : seb.toCheck) { |
| if (seb.envir == access.getFrame()) { |
| final String name= access.getSegmentName(); |
| if (name == null || commonNames.containsKey(name)) { |
| continue; |
| } |
| commonNames.put(name, FIRST); |
| seb.children.add(new RSourceElementByElementAccess.RVariable(seb.element, |
| (seb.envir != this.topLevelEnvir) ? RElement.R_GENERAL_LOCAL_VARIABLE : RElement.R_GENERAL_VARIABLE, |
| access )); |
| } |
| else { |
| // seb.children.add(new RSourceElementFromElementAccess.RVariable(seb.element, |
| // RLangElement.R_COMMON_VARIABLE, access)); |
| } |
| } |
| |
| final RSourceElementByElementAccess[] finalChildren= seb.children.toArray(new @NonNull RSourceElementByElementAccess[seb.children.size()]); |
| Arrays.sort(finalChildren, SOURCEELEMENT_SORTER); |
| if (finalChildren.length > 0) { |
| seb.element.setSourceChildren(ImCollections.newList(finalChildren)); |
| } |
| |
| commonNames.clear(); |
| classNames.clear(); |
| importNames.clear(); |
| } |
| |
| if (this.chunkElements != null) { |
| final HashMap<String, Integer> names= commonNames; |
| for (final EmbeddedRBuildElement element : this.chunkElements) { |
| final String name= element.getElementName().getDisplayName(); |
| final Integer occ= names.get(name); |
| if (occ == null) { |
| names.put(name, FIRST); |
| } |
| else { |
| names.put(name, Integer.valueOf( |
| (element.occurrenceCount= occ + 1) )); |
| } |
| } |
| for (final EmbeddedRBuildElement element : this.inlineElements) { |
| final String name= element.getElementName().getDisplayName(); |
| final Integer occ= names.get(name); |
| if (occ == null) { |
| names.put(name, FIRST); |
| } |
| else { |
| names.put(name, Integer.valueOf( |
| (element.occurrenceCount= occ + 1) )); |
| } |
| } |
| } |
| } |
| finally { |
| commonNames.clear(); |
| classNames.clear(); |
| importNames.clear(); |
| } |
| } |
| |
| private void cleanup() { |
| clean(this.currentEnvironments); |
| clean(this.idComponents); |
| this.argValueToIgnore.clear(); |
| clean(this.sourceContainerBuilders); |
| |
| this.ast= null; |
| this.genericDefaultEnvir= null; |
| this.globalEnvir= null; |
| this.packageRefs= null; |
| this.topLevelEnvir= null; |
| this.frames= null; |
| this.dependencyEnvironments= null; |
| |
| this.returnValue= null; |
| this.currentSourceContainerBuilder= null; |
| } |
| |
| private void clean(final ArrayList<?> list) { |
| if (list.size() > 2048) { |
| list.clear(); |
| list.trimToSize(); |
| list.ensureCapacity(1024); |
| } |
| else { |
| list.clear(); |
| } |
| } |
| |
| |
| private BuildSourceFrame getPkgEnvir(final String name) { |
| final String id= BuildSourceFrame.createId(RFrame.PACKAGE, name, ++this.anonymCount); |
| BuildSourceFrame envir= this.dependencyEnvironments.get(id); |
| if (envir == null) { |
| envir= new BuildSourceFrame.DefScope(RFrame.PACKAGE, id, name, new @NonNull BuildSourceFrame[0]); |
| this.dependencyEnvironments.put(id, envir); |
| } |
| return envir; |
| } |
| |
| private @Nullable SourceElementBuilder getCurrentSourceContainerBuilder() { |
| return this.currentSourceContainerBuilder; |
| } |
| |
| private @Nullable SourceElementBuilder getCurrentSourceContainerBuilder(final int type) { |
| final SourceElementBuilder containerBuilder= this.currentSourceContainerBuilder; |
| return (containerBuilder != null && (type == 0 || containerBuilder.element.getElementType() == type)) ? |
| containerBuilder : |
| null; |
| } |
| |
| private void registerInEnvir(final int search, final String name, final ElementAccess access) { |
| if (access.shared != null) { |
| return; |
| } |
| switch (search) { |
| case S_LOCAL: |
| this.topScope.add(name, access); |
| return; |
| case S_GLOBAL: |
| this.globalEnvir.add(name, access); |
| return; |
| case S_SEARCH: |
| this.topScope.addLateResolve(name, access); |
| return; |
| default: |
| throw new IllegalArgumentException("Illegal mode"); //$NON-NLS-1$ |
| } |
| } |
| |
| private ElementAccess registerSimpleClassAccessInEnvir(final RAstNode refNode, final RAstNode nameNode) { |
| final ElementAccess access= new ElementAccess.Class(refNode); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= nameNode; |
| this.genericDefaultEnvir.addClass(nameNode.getText(), access); |
| |
| return access; |
| } |
| |
| protected final void enterElement(final BuildSourceFrameElement element, final BuildSourceFrame envir, final RAstNode node) { |
| final SourceElementBuilder containerBuilder= new SourceElementBuilder(element, this.currentSourceContainerBuilder, envir); |
| envir.addFrameElement(element); |
| this.frames.put(envir.getFrameId(), envir); |
| node.addAttachment(envir); |
| this.currentSourceContainerBuilder= containerBuilder; |
| this.sourceContainerBuilders.add(containerBuilder); |
| } |
| |
| protected final void addEnvirInsteadOfElement(final BuildSourceFrame envir, final RAstNode node) { |
| this.frames.put(envir.getFrameId(), envir); |
| node.addAttachment(envir); |
| } |
| |
| protected final void leaveElement() { |
| this.currentSourceContainerBuilder= this.currentSourceContainerBuilder.parent; |
| } |
| |
| private @Nullable Object registerSourceElement(final @Nullable Object value, final ElementAccess access) { |
| if (value instanceof RSourceElementByElementAccess) { |
| final RSourceElementByElementAccess element= (RSourceElementByElementAccess) value; |
| if ((element.getElementType() & LtkModelElement.MASK_C1) == LtkModelElement.C1_METHOD) { |
| registerFunctionElement((RMethod)value, element.getElementType(), access, null); |
| return null; |
| } |
| |
| element.setAccess(access); |
| this.currentSourceContainerBuilder.children.add(element); |
| access.getNode().addAttachment(element); |
| return null; |
| } |
| else if (access.getSegmentName() != null && access.getType() == RElementName.MAIN_DEFAULT && access.nextSegment == null) { |
| this.currentSourceContainerBuilder.toCheck.add(access); |
| } |
| return value; |
| } |
| |
| private void registerAnonFunctionElement(final RMethod rMethod, final RFrame<RLangSourceElement> frame) { |
| final AnonymousAccess access= new AnonymousAccess(rMethod.getFDefNode(), frame); |
| rMethod.complete(access, createMethodArgDef(rMethod.getFDefNode(), null)); |
| access.getNode().addAttachment(rMethod); |
| } |
| |
| private void registerFunctionElement(final RMethod rMethod, int type, |
| final ElementAccess access, final @Nullable Signature sig) { |
| if (rMethod.getElementType() == RElement.R_COMMON_FUNCTION) { |
| final RFrame<?> frame= access.getFrame(); |
| if (frame != null && (frame.getFrameType() == RFrame.FUNCTION || frame.getFrameType() == RFrame.CLASS)) { |
| // make sure it is marked as local |
| type |= 0x1; |
| } |
| } |
| rMethod.complete(type, access, createMethodArgDef(rMethod.getFDefNode(), sig)); |
| final @Nullable ElementAccess[] argNameAccesses; |
| if (sig != null && (argNameAccesses= sig.argNameAccesses) != null) { |
| final BuildSourceFrame buildFrame= rMethod.getBuildFrame(); |
| for (int i= 0; i < argNameAccesses.length; i++) { |
| final ElementAccess argNameAccess= argNameAccesses[i]; |
| if (argNameAccess != null) { |
| buildFrame.add(argNameAccess.nameNode.getText(), argNameAccess); |
| } |
| } |
| } |
| |
| access.flags |= ElementAccess.A_FUNC; |
| this.currentSourceContainerBuilder.children.add(rMethod); |
| access.getNode().addAttachment(rMethod); |
| } |
| |
| private void registerFunctionElement(final RMethod rMethod) { |
| this.currentSourceContainerBuilder.children.add(rMethod); |
| rMethod.getAccess().getNode().addAttachment(rMethod); |
| } |
| |
| |
| private void registerClassElement(final RClass rClass) { |
| this.currentSourceContainerBuilder.children.add(rClass); |
| rClass.getAccess().getNode().addAttachment(rClass); |
| } |
| |
| private void registerClassExtElement(final RClassExt rClassExt) { |
| this.currentSourceContainerBuilder.children.add(rClassExt); |
| rClassExt.getAccess().getNode().addAttachment(rClassExt); |
| } |
| |
| |
| private boolean isRequested(final int requestId) { |
| for (int i= 0; i < this.request.length; i++) { |
| if (this.request[i] == requestId) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private @Nullable Object pollReturnValue() { |
| final Object returnValue= this.returnValue; |
| this.returnValue= null; |
| return returnValue; |
| } |
| |
| private @Nullable Object evalArgValue(final RAstNode node, final int @Nullable [] request) throws InvocationTargetException { |
| final int[] prevRequest= this.request; |
| if (request != null) { |
| this.request= request; |
| } |
| this.returnValue= null; |
| node.acceptInR(this); |
| this.argValueToIgnore.add(node); |
| this.request= prevRequest; |
| return pollReturnValue(); |
| } |
| |
| |
| @Override |
| public void visit(final SourceComponent node) throws InvocationTargetException { |
| throw new IllegalArgumentException(); |
| } |
| |
| @Override |
| public void visit(final Assignment node) throws InvocationTargetException { |
| // Value |
| this.returnValue= null; |
| node.getSourceChild().acceptInR(this); |
| final Object returnValue= this.returnValue; |
| |
| if (node.getNodeType() == NodeType.A_COLON) { |
| this.returnValue= null; |
| return; |
| } |
| |
| // TODO add direct support for fcall() <- source |
| final RAstNode target= node.getTargetChild(); |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE; |
| |
| final String name= resolveElementName(target, access, true); |
| if (name != null || returnValue instanceof RSourceElementByElementAccess) { |
| // Resolve |
| int mode; |
| if (access.getNextSegment() == null) { |
| switch (node.getOperator(0)) { |
| case ARROW_LEFT_D: |
| case ARROW_RIGHT_D: |
| mode= S_SEARCH; |
| break; |
| default: |
| mode= S_LOCAL; |
| break; |
| } |
| } |
| else { |
| mode= S_SEARCH; |
| } |
| registerInEnvir(mode, name, access); |
| |
| this.returnValue= registerSourceElement(returnValue, access); |
| } |
| else { |
| this.returnValue= null; |
| } |
| } |
| |
| @Override |
| public void visit(final CForLoop node) throws InvocationTargetException { |
| final Symbol symbol= node.getVarChild(); |
| final ElementAccess access= new ElementAccess.Default(symbol); |
| access.flags= ElementAccess.A_WRITE; |
| final String name= resolveElementName(symbol, access, false); |
| if (name != null) { |
| registerInEnvir(S_LOCAL, name, access); |
| } |
| this.request= NO_REQUESTS; |
| node.getCondChild().acceptInR(this); |
| node.getContChild().acceptInR(this); |
| |
| this.returnValue= null; |
| } |
| |
| |
| @Override |
| public void visit(final FDef node) throws InvocationTargetException { |
| final BuildSourceFrame envir= new BuildSourceFrame.DefScope(RFrame.FUNCTION, |
| BuildSourceFrame.createId(RFrame.FUNCTION, null, ++this.anonymCount), |
| null, new @NonNull BuildSourceFrame[] { this.topScope } ); |
| this.currentEnvironments.add(envir); |
| this.topScope= envir; |
| |
| final RMethod rMethod; |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| rMethod= new RMethod(containerBuilder.element, envir, node); |
| enterElement(rMethod, envir, node); |
| } |
| else { |
| rMethod= null; |
| addEnvirInsteadOfElement(envir, node); |
| } |
| |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| if (rMethod != null) { |
| leaveElement(); |
| } |
| |
| this.currentEnvironments.remove(envir); |
| this.topScope= this.currentEnvironments.get(this.currentEnvironments.size() - 1); |
| |
| this.returnValue= rMethod; |
| } |
| |
| @Override |
| public void visit(final FDef.Arg node) throws InvocationTargetException { |
| final RAstNode nameNode= node.getNameChild(); |
| if ((nameNode.getStatusCode() & RSourceConstants.STATUSFLAG_REAL_ERROR) == 0) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE | ElementAccess.A_ARG; |
| access.nameNode= nameNode; |
| registerInEnvir(S_LOCAL, nameNode.getText(), access); |
| |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| containerBuilder.children.add(new RSourceElementByElementAccess.RVariable( |
| containerBuilder.element, RElement.R_ARGUMENT, access)); |
| } |
| } |
| |
| if (node.hasDefault()) { |
| node.getDefaultChild().acceptInR(this); |
| } |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final FCall node) throws InvocationTargetException { |
| // Resolve |
| final RAstNode ref= node.getRefChild(); |
| final ElementAccess access= new ElementAccess.Default(node, ref); |
| access.flags= ElementAccess.A_CALL | ElementAccess.A_FUNC; |
| |
| final String name= resolveElementName(node.getRefChild(), access, true); |
| if (name != null) { |
| registerInEnvir(S_SEARCH, name, access); |
| } |
| final boolean write; |
| final RAstNode parent= node.getRParent(); |
| switch ((parent != null) ? parent.getNodeType() : NodeType.DUMMY) { |
| case A_LEFT: |
| case A_RIGHT: |
| case A_EQUALS: |
| write= (((Assignment)parent).getTargetChild() == node); |
| break; |
| default: |
| write= false; |
| break; |
| } |
| |
| FCallAnalyzer specialist= null; |
| if (name != null) { |
| specialist= this.fCallAnalyzers.get(name); |
| } |
| if (specialist == null) { |
| specialist= this.fCallFallback; |
| } |
| specialist.visit(node, write); |
| } |
| |
| @Override |
| public void visit(final FCall.Arg node) throws InvocationTargetException { |
| final RAstNode valueNode= node.getValueChild(); |
| if (valueNode != null) { |
| if (!this.argValueToIgnore.remove(valueNode)) { |
| valueNode.acceptInR(this); |
| } |
| } |
| |
| this.returnValue= null; |
| } |
| |
| public @Nullable RMethod visitAndCheckValue(final FCall. @Nullable Arg node, final String name) throws InvocationTargetException { |
| if (node != null) { |
| final RAstNode valueNode= node.getValueChild(); |
| if (valueNode != null) { |
| final Object value= evalArgValue(valueNode, NO_REQUESTS); |
| if (value instanceof RMethod) { |
| final RMethod rMethod= (RMethod)value; |
| |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE | ElementAccess.A_FUNC; |
| access.nameNode= node.getNameChild(); |
| this.currentSourceContainerBuilder.envir.addRunResolve(name, access); |
| |
| registerFunctionElement(rMethod, RElement.R_COMMON_LOCAL_FUNCTION, access, null); |
| return rMethod; |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void visit(final SubIndexed.Arg node) throws InvocationTargetException { |
| final RAstNode valueNode= node.getValueChild(); |
| if (valueNode != null) { |
| valueNode.acceptInR(this); |
| } |
| } |
| |
| @Override |
| public void visit(final NSGet node) throws InvocationTargetException { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| final String name= resolveElementName(node, access); |
| if (name != null) { |
| registerInEnvir(S_LOCAL, name, access); |
| } |
| |
| this.returnValue= access; |
| } |
| |
| @Override |
| public void visit(final Symbol node) throws InvocationTargetException { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| final String name= resolveElementName(node, access); |
| if (name != null) { |
| registerInEnvir(S_SEARCH, name, access); |
| |
| if (name.equals(".GlobalEnv")) { |
| this.returnValue= this.globalEnvir; |
| return; |
| } |
| } |
| |
| this.returnValue= access; |
| } |
| |
| @Override |
| public void visit(final SubNamed node) throws InvocationTargetException { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| final String name= resolvePartName(node, access); |
| if (name != null) { |
| registerInEnvir(S_SEARCH, name, access); |
| } |
| |
| this.returnValue= access; |
| } |
| |
| @Override |
| public void visit(final SubIndexed node) throws InvocationTargetException { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| final String name= resolveElementName(node, access); |
| if (name != null) { |
| registerInEnvir(S_SEARCH, name, access); |
| } |
| |
| this.returnValue= access; |
| } |
| |
| @Override |
| public void visit(final Model node) throws InvocationTargetException { |
| node.acceptInRChildren(this); |
| this.returnValue= node; |
| } |
| |
| |
| @Override |
| public void visit(final Help node) throws InvocationTargetException { |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final StringConst node) throws InvocationTargetException { |
| for (int i= 0; i < this.request.length; i++) { |
| if (this.request[i] == RETURN_STRING_ARRAY) { |
| this.returnValue= new NodeArray(RETURN_STRING_ARRAY, new StringConst[] { node }); |
| return; |
| } |
| } |
| this.returnValue= node; |
| } |
| |
| @Override |
| public void visit(final NumberConst node) throws InvocationTargetException { |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final NullConst node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| |
| @Override |
| public void visit(final Special node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Sign node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Power node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Arithmetic node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Seq node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Relational node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Logical node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final CIfElse node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final CRepeatLoop node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final CWhileLoop node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final CLoopCommand node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| @Override |
| public void visit(final Dummy node) throws InvocationTargetException { |
| this.request= NO_REQUESTS; |
| node.acceptInRChildren(this); |
| |
| this.returnValue= null; |
| } |
| |
| |
| private static boolean isValidPackageName(final RAstNode node) { |
| switch (node.getNodeType()) { |
| case SYMBOL: |
| return ((node.getStatusCode() & RSourceConstants.STATUSFLAG_REAL_ERROR) == 0); |
| case STRING_CONST: |
| // TODO check |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| private static boolean isTextEqualTo(final RAstNode node, final String text) { |
| return text.equals(node.getText()); |
| } |
| |
| private @Nullable String resolveElementName(final RAstNode node, final ElementAccess access, |
| final boolean allowString) throws InvocationTargetException { |
| switch (node.getNodeType()) { |
| case SYMBOL: |
| return resolveElementName((Symbol) node, access); |
| case STRING_CONST: |
| if (allowString && ((node.getStatusCode() & RSourceConstants.STATUSFLAG_REAL_ERROR) == 0)) { |
| access.nameNode= node; |
| return node.getText(); |
| } |
| return null; |
| case SUB_INDEXED_S: |
| case SUB_INDEXED_D: |
| return resolveElementName((SubIndexed) node, access); |
| case SUB_NAMED_PART: |
| return resolvePartName((SubNamed) node, access); |
| case SUB_NAMED_SLOT: |
| return resolveSlotName((SubNamed) node, access); |
| case NS_GET: |
| case NS_GET_INT: |
| return resolveElementName((NSGet) node, access); |
| default: |
| break; |
| } |
| if (node == access.fullNode) { |
| node.acceptInRChildren(this); |
| } |
| else { |
| node.acceptInR(this); |
| } |
| return null; |
| } |
| |
| private @Nullable String resolveElementName(final Symbol node, final ElementAccess access) { |
| if ((node.getStatusCode() & RSourceConstants.STATUSFLAG_REAL_ERROR) == 0) { |
| access.nameNode= node; |
| return node.getText(); |
| } |
| return null; |
| } |
| |
| private @Nullable String resolveElementName(final SubIndexed node, final ElementAccess access) |
| throws InvocationTargetException { |
| final RAstNode child= node.getRefChild(); |
| final String name= resolveElementName(child, access, false); |
| node.getArgsChild().acceptInR(this); |
| if (name != null) { |
| access.flags |= ElementAccess.A_SUB; |
| access.appendSubElement((node.getOperator(0) == RTerminal.SUB_INDEXED_D_OPEN) ? |
| new SubIndexedDElementAccess(access, node) : new SubIndexedSElementAccess(access, node)); |
| return name; |
| } |
| return null; |
| } |
| |
| private @Nullable String resolvePartName(final SubNamed node, final ElementAccess access) |
| throws InvocationTargetException { |
| final RAstNode child= node.getRefChild(); |
| final String name= resolveElementName(child, access, false); |
| if (name != null) { |
| access.flags |= ElementAccess.A_SUB; |
| access.appendSubElement(new SubNamedPartSyntacticElementAccess(access, node)); |
| return name; |
| } |
| return null; |
| } |
| |
| private @Nullable String resolveSlotName(final SubNamed node, final ElementAccess access) |
| throws InvocationTargetException { |
| final RAstNode child= node.getRefChild(); |
| final String name= resolveElementName(child, access, false); |
| if (name != null) { |
| access.flags |= ElementAccess.A_SUB; |
| access.appendSubElement(new SubNamedSlotSyntacticElementAccess(access, node)); |
| return name; |
| } |
| return null; |
| } |
| |
| private @Nullable String resolveElementName(final NSGet node, final ElementAccess access) { |
| final RAstNode namespaceChild= node.getNamespaceChild(); |
| final RAstNode elementChild= node.getElementChild(); |
| final String namespaceName= (isValidPackageName(namespaceChild)) ? namespaceChild.getText() : null; |
| if (namespaceName != null) { |
| final ElementAccess packageAccess= (node.getNodeType() == NodeType.NS_GET_INT) ? |
| new ElementAccess.NamespaceInternal(access.fullNode, namespaceChild) : |
| new ElementAccess.Namespace(access.fullNode, namespaceChild); |
| if (namespaceName != null) { |
| this.packageRefs.add(namespaceName, packageAccess); |
| } |
| |
| if (access instanceof ElementAccess.Main) { |
| ((ElementAccess.Main) access).setScope(packageAccess); |
| } |
| } |
| // register explicit |
| BuildSourceFrame envir; |
| if (namespaceName != null && |
| ((elementChild.getStatusCode() & RSourceConstants.STATUSFLAG_REAL_ERROR) == 0)) { |
| envir= getPkgEnvir(namespaceName); |
| } |
| else { |
| envir= this.topScope; |
| } |
| access.nameNode= elementChild; |
| envir.add(elementChild.getText(), access); |
| return null; // prevent registering in top env |
| } |
| |
| |
| protected static interface FCallAnalyzer { |
| |
| public void visit(FCall node, boolean assignment) throws InvocationTargetException; |
| |
| } |
| |
| protected class CommonVarNamedRead implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_name; |
| private final int argIdx_scope; |
| |
| protected CommonVarNamedRead(final ArgsDefinition argsDef, final String nameArgName, final String scopeArgName) { |
| this.argsDef= argsDef; |
| this.argIdx_name= this.argsDef.indexOf(nameArgName); |
| this.argIdx_scope= this.argsDef.indexOf(scopeArgName); |
| } |
| |
| @Override |
| public final void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode nameValue= args.getArgValueNode(this.argIdx_name); |
| |
| if (nameValue != null && nameValue.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= nameValue; |
| final BuildSourceFrame envir= readScopeArgs(args.getArgValueNode(this.argIdx_scope), SourceAnalyzer.this.topScope); |
| if (toJavaBooleanValue(args.getArgValueNode("inherits"), false)) { |
| envir.addLateResolve(nameValue.getText(), access); |
| } |
| else { |
| envir.add(nameValue.getText(), access); |
| } |
| |
| SourceAnalyzer.this.argValueToIgnore.add(nameValue); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class CommonDefBased implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public CommonDefBased(final ArgsDefinition argsDef) { |
| this.argsDef= argsDef; |
| } |
| |
| |
| private boolean matchesNameType(final int nameType, final int defType, final RAstNode argValue) { |
| return ((defType & nameType) != 0 |
| && ( ((defType & ArgsDefinition.NAME_AS_STRING) != 0 |
| && argValue.getNodeType() == NodeType.STRING_CONST ) |
| || ((defType & ArgsDefinition.NAME_AS_SYMBOL) != 0 |
| && argValue.getNodeType() == NodeType.SYMBOL )) |
| && argValue.getText() != null ); |
| } |
| |
| @Override |
| public final void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| |
| ITER_ARGS: for (int i= 0; i < args.allocatedArgs.length; i++) { |
| final RAstNode argValue= args.getArgValueNode(i); |
| if (argValue != null) { |
| if (matchesNameType(ArgsDefinition.PACKAGE_NAME, this.argsDef.get(i).type, argValue)) { |
| final ElementAccess access= new ElementAccess.Namespace(node, argValue); |
| access.nameNode= argValue; |
| @SuppressWarnings("null") |
| final @NonNull String packageName= argValue.getText(); |
| SourceAnalyzer.this.packageRefs.add(packageName, access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(argValue); |
| continue ITER_ARGS; |
| } |
| if ((this.argsDef.get(i).type & ArgsDefinition.METHOD_NAME) != 0 |
| && argValue.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ | ElementAccess.A_FUNC; |
| access.nameNode= argValue; |
| SourceAnalyzer.this.genericDefaultEnvir.addLateResolve(argValue.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(argValue); |
| continue ITER_ARGS; |
| } |
| if ((this.argsDef.get(i).type & ArgsDefinition.CLASS_NAME) != 0 |
| && argValue.getNodeType() == NodeType.STRING_CONST) { |
| registerSimpleClassAccessInEnvir(node, argValue); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(argValue); |
| continue ITER_ARGS; |
| } |
| if ((this.argsDef.get(i).type & ArgsDefinition.UNSPECIFIC_NAME) != 0 |
| && argValue.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= argValue; |
| SourceAnalyzer.this.topScope.addLateResolve(argValue.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(argValue); |
| continue ITER_ARGS; |
| } |
| if (matchesNameType(ArgsDefinition.HELP_TOPIC_NAME, this.argsDef.get(i).type, argValue)) { |
| SourceAnalyzer.this.argValueToIgnore.add(argValue); |
| continue ITER_ARGS; |
| } |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| |
| protected final class BaseAssign implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_x; |
| private final int argIdx_value; |
| |
| |
| public BaseAssign(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_ASSIGN_args; |
| this.argIdx_x= this.argsDef.indexOf("x"); |
| this.argIdx_value= this.argsDef.indexOf("value"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.returnValue= null; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode xNode= args.getArgValueNode(this.argIdx_x); |
| final RAstNode valueNode= args.getArgValueNode(this.argIdx_value); |
| |
| Object returnValue= null; |
| if (valueNode != null) { |
| returnValue= evalArgValue(valueNode, null); |
| } |
| if (xNode != null && xNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE; |
| access.nameNode= xNode; |
| |
| final BuildSourceFrame envir= readScopeArgs(args.getArgValueNode("pos"), SourceAnalyzer.this.topScope); |
| if (toJavaBooleanValue(args.getArgValueNode("inherits"), false)) { |
| envir.addLateResolve(xNode.getText(), access); |
| } |
| else { |
| envir.add(xNode.getText(), access); |
| } |
| |
| returnValue= registerSourceElement(returnValue, access); |
| } |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= returnValue; |
| } |
| |
| } |
| |
| protected final class BaseRemove implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public BaseRemove(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_REMOVE_args; |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| |
| if (args.ellipsisArgs.length > 0) { |
| for (int i= 0; i < args.ellipsisArgs.length; i++) { |
| final FCall.Arg argNode= args.ellipsisArgs[i]; |
| final RAstNode valueNode= argNode.getValueChild(); |
| if (valueNode != null) { |
| switch (valueNode.getNodeType()) { |
| case SYMBOL: |
| case STRING_CONST: |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_DELETE; |
| access.nameNode= valueNode; |
| final BuildSourceFrame envir= readScopeArgs(args.getArgValueNode("pos"), SourceAnalyzer.this.topScope); |
| if (toJavaBooleanValue(args.getArgValueNode("inherits"), false)) { |
| envir.addLateResolve(valueNode.getText(), access); |
| } |
| else { |
| envir.add(valueNode.getText(), access); |
| } |
| |
| SourceAnalyzer.this.argValueToIgnore.add(valueNode); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class BaseExists extends CommonVarNamedRead { |
| |
| public BaseExists(final RCoreFunctions rdef) { |
| super(rdef.BASE_EXISTS_args, "x", "where"); |
| } |
| |
| } |
| |
| protected final class BaseGet implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_x; |
| private final int argIdx_scope; |
| |
| public BaseGet(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_GET_args; |
| this.argIdx_x= this.argsDef.indexOf("x"); |
| this.argIdx_scope= this.argsDef.indexOf("pos"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode xNode= args.getArgValueNode(this.argIdx_x); |
| |
| if (xNode != null && xNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= xNode; |
| final BuildSourceFrame envir= readScopeArgs(args.getArgValueNode(this.argIdx_scope), SourceAnalyzer.this.topScope); |
| if (toJavaBooleanValue(args.getArgValueNode("inherits"), true)) { |
| envir.addLateResolve(xNode.getText(), access); |
| } |
| else { |
| envir.add(xNode.getText(), access); |
| } |
| |
| SourceAnalyzer.this.argValueToIgnore.add(xNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class BaseSave implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public BaseSave(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_SAVE_args; |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| |
| if (args.ellipsisArgs.length > 0) { |
| for (int i= 0; i < args.ellipsisArgs.length; i++) { |
| final FCall.Arg argNode= args.ellipsisArgs[i]; |
| final RAstNode valueNode= argNode.getValueChild(); |
| if (valueNode != null) { |
| switch (valueNode.getNodeType()) { |
| case SYMBOL: |
| case STRING_CONST: |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= valueNode; |
| SourceAnalyzer.this.topScope.addLateResolve(valueNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(valueNode); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class BaseCall implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| |
| public BaseCall(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_CALL_args; |
| this.argIdx_fName= this.argsDef.indexOf("name"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode nameNode= args.getArgValueNode(this.argIdx_fName); |
| |
| if (nameNode != null && nameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ | ElementAccess.A_FUNC; |
| access.nameNode= nameNode; |
| SourceAnalyzer.this.topScope.addLateResolve(nameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(nameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class BaseDoCall implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| |
| public BaseDoCall(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_DOCALL_args; |
| this.argIdx_fName= this.argsDef.indexOf("what"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode nameNode= args.getArgValueNode(this.argIdx_fName); |
| |
| if (nameNode != null) { |
| final ElementAccess access= new ElementAccess.Default(node, nameNode); |
| access.flags= ElementAccess.A_CALL | ElementAccess.A_FUNC; |
| final String name= resolveElementName(nameNode, access, true); |
| if (name != null) { |
| SourceAnalyzer.this.topScope.addLateResolve(name, access); |
| } |
| SourceAnalyzer.this.argValueToIgnore.add(nameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| private abstract class BaseCommonPackageLoad implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_packageName; |
| private final int argIdx_stringOnly; |
| |
| public BaseCommonPackageLoad(final ArgsDefinition argsDef) { |
| this.argsDef= argsDef; |
| this.argIdx_packageName= this.argsDef.indexOf("package"); |
| this.argIdx_stringOnly= this.argsDef.indexOf("character.only"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode nameValue= args.getArgValueNode(this.argIdx_packageName); |
| if (nameValue != null |
| && (nameValue.getNodeType() == NodeType.STRING_CONST |
| || (!toJavaBooleanValue(args.getArgNode(this.argIdx_stringOnly), false) && nameValue.getNodeType() == NodeType.SYMBOL)) |
| && isValidPackageName(nameValue)) { |
| final String packageName= node.getText(); |
| if (packageName != null) { |
| final ElementAccess access= new ElementAccess.Package( |
| node, nameValue); |
| access.flags |= ElementAccess.A_IMPORT; |
| SourceAnalyzer.this.packageRefs.add(packageName, access); |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| final RPkgImport rImport= new RPkgImport(containerBuilder.element, access); |
| containerBuilder.children.add(rImport); |
| } |
| |
| final BuildSourceFrame envir= getPkgEnvir(packageName); |
| if (!SourceAnalyzer.this.globalEnvir.parents.contains(envir)) { |
| SourceAnalyzer.this.globalEnvir.parents= ImCollections.addElement(SourceAnalyzer.this.globalEnvir.parents, 0, envir); |
| } |
| } |
| |
| SourceAnalyzer.this.argValueToIgnore.add(nameValue); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= SourceAnalyzer.this.globalEnvir; |
| } |
| |
| } |
| |
| protected final class BaseLibrary extends BaseCommonPackageLoad { |
| |
| public BaseLibrary(final RCoreFunctions rdef) { |
| super(rdef.BASE_LIBRARY_args); |
| } |
| |
| } |
| |
| protected final class BaseRequire extends BaseCommonPackageLoad { |
| |
| public BaseRequire(final RCoreFunctions rdef) { |
| super(rdef.BASE_REQUIRE_args); |
| } |
| |
| } |
| |
| |
| protected final class BaseGlobalenv implements FCallAnalyzer { |
| |
| public BaseGlobalenv(final RCoreFunctions rdef) { |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= SourceAnalyzer.this.globalEnvir; |
| } |
| |
| } |
| |
| protected final class BaseTopenv implements FCallAnalyzer { |
| |
| public BaseTopenv(final RCoreFunctions rdef) { |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| // final RAstNode envir= resolveEnvir(argValues, this.argsDef); |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= SourceAnalyzer.this.topLevelEnvir; |
| } |
| |
| } |
| |
| protected final class BaseC implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public BaseC(final RCoreFunctions rdef) { |
| this.argsDef= rdef.BASE_C_args; |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| Object returnValue= null; |
| REQUEST: for (int i= 0; i < SourceAnalyzer.this.request.length; i++) { |
| if (SourceAnalyzer.this.request[i] == RETURN_STRING_ARRAY) { |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode[] array= new @NonNull RAstNode[args.ellipsisArgs.length]; |
| for (int j= 0; j < array.length; j++) { |
| final FCall.Arg argNode= args.ellipsisArgs[j]; |
| final RAstNode valueNode= argNode.getValueChild(); |
| if (valueNode != null) { |
| if (valueNode.getNodeType() == NodeType.STRING_CONST) { |
| array[j]= valueNode; |
| SourceAnalyzer.this.argValueToIgnore.add(valueNode); |
| } |
| else { |
| break REQUEST; |
| } |
| } |
| } |
| returnValue= new NodeArray(RETURN_STRING_ARRAY, array); |
| break REQUEST; |
| } |
| } |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= returnValue; |
| } |
| |
| } |
| |
| private abstract class MethodsCommonSetGeneric implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| private final int argIdx_def; |
| private final int argIdx_useAsDefault; |
| private final int argIdx_genericFunction; |
| private final int argIdx_signature; |
| |
| protected MethodsCommonSetGeneric(final ArgsDefinition argsDef) { |
| this.argsDef= argsDef; |
| this.argIdx_fName= this.argsDef.indexOf("name"); |
| this.argIdx_def= this.argsDef.indexOf("def"); |
| this.argIdx_useAsDefault= this.argsDef.indexOf("useAsDefault"); |
| this.argIdx_genericFunction= this.argsDef.indexOf("genericFunction"); |
| this.argIdx_signature= this.argsDef.indexOf("signature"); |
| } |
| |
| @Override |
| public final void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode fNameNode= args.getArgValueNode(this.argIdx_fName); |
| |
| if (fNameNode != null && fNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE | ElementAccess.A_FUNC; |
| access.nameNode= fNameNode; |
| SourceAnalyzer.this.topLevelEnvir.add(fNameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(fNameNode); |
| |
| final BuildSourceFrame envir= new BuildSourceFrame.RunScope(RFrame.FUNCTION, BuildSourceFrame.createId(RFrame.FUNCTION, access.getSegmentName(), ++SourceAnalyzer.this.anonymCount), SourceAnalyzer.this.topScope); |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| final RMethod rMethod= new RMethod(containerBuilder.element, |
| RElement.R_GENERIC_FUNCTION, access, envir); |
| registerFunctionElement(rMethod); |
| |
| enterElement(rMethod, envir, node); |
| |
| final RMethod defMethod= visitAndCheckValue(args.getArgNode(this.argIdx_def), "def"); |
| final RMethod defaultMethod= visitAndCheckValue(args.getArgNode(this.argIdx_useAsDefault), "useAsDefault"); |
| visitAndCheckValue(args.getArgNode(this.argIdx_genericFunction), "genericFunction"); |
| |
| final RAstNode signatureValue= args.getArgValueNode(this.argIdx_signature); |
| RAstNode[] signatureArgNodes= null; |
| if (signatureValue != null) { |
| final Object value= evalArgValue(signatureValue, STRING_ARRAY_REQUEST); |
| if (value instanceof ReturnValue && ((ReturnValue)value).returnType == RETURN_STRING_ARRAY) { |
| signatureArgNodes= ((NodeArray)value).array; |
| } |
| } |
| |
| ArgsDefinition baseDef= null; |
| ArgsDefinition methodDef; |
| if (defMethod != null) { |
| baseDef= defMethod.getArgsDefinition(); |
| } |
| if (defaultMethod != null && (baseDef == null || baseDef.size() == 0)) { |
| baseDef= defaultMethod.getArgsDefinition(); |
| } |
| if (baseDef != null && baseDef.size() > 0) { |
| final ArgsBuilder argsBuilder= new ArgsBuilder(); |
| // we copy the names |
| if (signatureArgNodes != null) { // explicit |
| ARGS: for (int i= 0; i < baseDef.size(); i++) { |
| final String name= baseDef.get(i).name; |
| if (name != null) { |
| for (int j= 0; j < signatureArgNodes.length; j++) { |
| if (isTextEqualTo(signatureArgNodes[j], name)) { |
| argsBuilder.add(name, 0, "<?>"); |
| continue ARGS; |
| } |
| } |
| argsBuilder.add(name, 0, "\u2014"); |
| continue ARGS; |
| } |
| argsBuilder.add(name); |
| continue ARGS; |
| } |
| } |
| else if (baseDef.size() == 1 && "...".equals(baseDef.get(0).name)) { |
| argsBuilder.add("...", 0, "<?>"); |
| } |
| else { |
| ARGS: for (int i= 0; i < baseDef.size(); i++) { |
| final String name= baseDef.get(i).name; |
| if (name != null) { |
| if (!name.equals("...")) { |
| argsBuilder.add(name, 0, "<?>"); |
| continue ARGS; |
| } |
| argsBuilder.add(name, 0, "\u2014"); |
| continue ARGS; |
| } |
| argsBuilder.add(name); |
| continue ARGS; |
| } |
| } |
| methodDef= argsBuilder.build(); |
| } |
| else { |
| methodDef= new ArgsDefinition(); |
| } |
| rMethod.complete(methodDef); |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| |
| leaveElement(); |
| } |
| else { |
| addEnvirInsteadOfElement(envir, node); |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| } |
| } |
| else { |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| } |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsSetGeneric extends MethodsCommonSetGeneric { |
| |
| public MethodsSetGeneric(final RCoreFunctions rdef) { |
| super(rdef.METHODS_SETGENERIC_args); |
| } |
| |
| } |
| |
| protected final class MethodsSetGroupGeneric extends MethodsCommonSetGeneric { |
| |
| public MethodsSetGroupGeneric(final RCoreFunctions rdef) { |
| super(rdef.METHODS_SETGROUPGENERIC_args); |
| } |
| |
| } |
| |
| protected final class MethodsRemoveGeneric implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| |
| public MethodsRemoveGeneric(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETGROUPGENERIC_args; |
| this.argIdx_fName= this.argsDef.indexOf("f"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode fNameNode= args.getArgValueNode(this.argIdx_fName); |
| |
| if (fNameNode != null && fNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_DELETE | ElementAccess.A_FUNC; |
| access.nameNode= fNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.add(fNameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(fNameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsSignature implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public MethodsSignature(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SIGNATURE_args; |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| Object returnValue= null; |
| |
| if (args.ellipsisArgs.length > 0) { |
| final @Nullable ElementAccess[] argNameNodes= new @Nullable ElementAccess[args.ellipsisArgs.length]; |
| final @Nullable String[] classNames= new @Nullable String[args.ellipsisArgs.length]; |
| for (int i= 0; i < args.ellipsisArgs.length; i++) { |
| final FCall.Arg arg= args.ellipsisArgs[i]; |
| final RAstNode nameNode= arg.getNameChild(); |
| if (nameNode != null && nameNode.getText() != null) { |
| final ElementAccess access= new ElementAccess.Default(node, nameNode); |
| access.flags= ElementAccess.A_ARG; |
| argNameNodes[i]= access; |
| } |
| final RAstNode valueNode= arg.getValueChild(); |
| if (valueNode != null) { |
| if (valueNode.getNodeType() == NodeType.STRING_CONST) { |
| classNames[i]= valueNode.getText(); |
| registerSimpleClassAccessInEnvir(node, valueNode); |
| SourceAnalyzer.this.argValueToIgnore.add(valueNode); |
| } |
| } |
| } |
| returnValue= new Signature(argNameNodes, classNames); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= returnValue; |
| } |
| |
| } |
| |
| protected final class MethodsSetClass implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| private final int argIdx_superClasses; |
| private final int argIdx_representation; |
| private final int argIdx_prototype; |
| |
| public MethodsSetClass(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETCLASS_args; |
| this.argIdx_className= this.argsDef.indexOf("Class"); |
| this.argIdx_superClasses= this.argsDef.indexOf("contains"); |
| this.argIdx_representation= this.argsDef.indexOf("representation"); |
| this.argIdx_prototype= this.argsDef.indexOf("prototype"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_WRITE; |
| String name; |
| final RAstNode classNameValue= args.getArgValueNode(this.argIdx_className); |
| if (classNameValue != null && classNameValue.getNodeType() == NodeType.STRING_CONST) { |
| name= classNameValue.getText(); |
| access.nameNode= classNameValue; |
| SourceAnalyzer.this.argValueToIgnore.add(classNameValue); |
| } |
| else { |
| name= null; |
| } |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(name, access); |
| |
| final BuildSourceFrame envir= new BuildSourceFrame.RunScope(RFrame.CLASS, BuildSourceFrame.createId(RFrame.CLASS, access.getSegmentName(), ++SourceAnalyzer.this.anonymCount), |
| SourceAnalyzer.this.topScope); |
| |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| final RClass rClass= new RSourceElementByElementAccess.RClass(containerBuilder.element, access, envir); |
| registerClassElement(rClass); |
| enterElement(rClass, envir, node); |
| |
| final RAstNode representationValue= args.getArgValueNode(this.argIdx_representation); |
| if (representationValue != null) { |
| evalArgValue(representationValue, REPRESENTATION_REQUEST); |
| } |
| |
| final RAstNode superClassesValue= args.getArgValueNode(this.argIdx_superClasses); |
| if (superClassesValue != null) { |
| final Object value= evalArgValue(superClassesValue, STRING_ARRAY_REQUEST); |
| if (value instanceof ReturnValue && ((ReturnValue)value).returnType == RETURN_STRING_ARRAY) { |
| final RAstNode[] superClassNameNodes= ((NodeArray)value).array; |
| final RAstNode refNode= nonNullAssert(args.allocatedArgs[this.argIdx_superClasses]); |
| final @Nullable String[] names= new @Nullable String[superClassNameNodes.length]; |
| for (int i= 0; i < superClassNameNodes.length; i++) { |
| final ElementAccess superClassAccess= registerSimpleClassAccessInEnvir(refNode, superClassNameNodes[i]); |
| names[i]= superClassAccess.getSegmentName(); |
| } |
| rClass.addSuperClasses(names); |
| } |
| } |
| |
| final RAstNode prototypeValue= args.getArgValueNode(this.argIdx_prototype); |
| if (prototypeValue != null) { |
| evalArgValue(prototypeValue, PROTOTYPE_REQUEST); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| |
| leaveElement(); |
| } |
| else { |
| addEnvirInsteadOfElement(envir, node); |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| } |
| |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsSetClassUnion implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| private final int argIdx_superClassNames; |
| |
| public MethodsSetClassUnion(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETCLASSUNION_args; |
| this.argIdx_className= this.argsDef.indexOf("name"); |
| this.argIdx_superClassNames= this.argsDef.indexOf("members"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode classNameValue= args.getArgValueNode(this.argIdx_className); |
| final RAstNode superClassNamesValue= args.getArgValueNode(this.argIdx_superClassNames); |
| |
| final ElementAccess access= new ElementAccess.Class(node); |
| final String name; |
| access.flags= ElementAccess.A_WRITE; |
| if (classNameValue != null && classNameValue.getNodeType() == NodeType.STRING_CONST) { |
| name= classNameValue.getText(); |
| access.nameNode= classNameValue; |
| SourceAnalyzer.this.argValueToIgnore.add(classNameValue); |
| } |
| else { |
| name= null; |
| } |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(name, access); |
| |
| final BuildSourceFrame envir= new BuildSourceFrame.RunScope(RFrame.CLASS, BuildSourceFrame.createId(RFrame.CLASS, access.getSegmentName(), ++SourceAnalyzer.this.anonymCount), |
| SourceAnalyzer.this.topScope); |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| final RClass rClass= new RSourceElementByElementAccess.RClass(containerBuilder.element, access, envir); |
| registerClassElement(rClass); |
| enterElement(rClass, envir, node); |
| |
| if (superClassNamesValue != null) { |
| final Object value= evalArgValue(superClassNamesValue, STRING_ARRAY_REQUEST); |
| if (value instanceof ReturnValue && ((ReturnValue)value).returnType == RETURN_STRING_ARRAY) { |
| final RAstNode[] superClassNameNodes= ((NodeArray)value).array; |
| final RAstNode refNode= nonNullAssert(args.allocatedArgs[this.argIdx_superClassNames]); |
| final @Nullable String[] names= new @Nullable String[superClassNameNodes.length]; |
| for (int i= 0; i < superClassNameNodes.length; i++) { |
| final ElementAccess superClassAccess= registerSimpleClassAccessInEnvir(refNode, superClassNameNodes[i]); |
| names[i]= superClassAccess.getSegmentName(); |
| } |
| rClass.addSuperClasses(names); |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| |
| leaveElement(); |
| } |
| else { |
| addEnvirInsteadOfElement(envir, node); |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| } |
| |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsRepresentation implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public MethodsRepresentation(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_REPRESENTATION_args; |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| final SourceElementBuilder containerBuilder= (SourceAnalyzer.this.request == REPRESENTATION_REQUEST) ? |
| getCurrentSourceContainerBuilder(RElement.R_S4CLASS) : null; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| |
| if (args.ellipsisArgs.length > 0) { |
| final RSourceElementByElementAccess.RClass rClass= (containerBuilder != null) ? |
| (RSourceElementByElementAccess.RClass)containerBuilder.element : null; |
| final @Nullable String[] superClassNames= new @Nullable String[args.ellipsisArgs.length]; |
| |
| for (int i= 0; i < args.ellipsisArgs.length; i++) { |
| final FCall.Arg arg= args.ellipsisArgs[i]; |
| final RAstNode nameNode= arg.getNameChild(); |
| if (nameNode != null) { // slot |
| RSlot slot= null; |
| if (containerBuilder != null) { |
| final ElementAccess.Slot access= new ElementAccess.Slot(arg); |
| access.flags= ElementAccess.A_WRITE; |
| access.nameNode= nameNode; |
| containerBuilder.envir.addRunResolve(nameNode.getText(), access); |
| slot= new RSourceElementByElementAccess.RSlot(rClass, access); |
| containerBuilder.children.add(slot); |
| } |
| final RAstNode valueNode= arg.getValueChild(); |
| if (valueNode != null) { |
| if (valueNode.getNodeType() == NodeType.STRING_CONST) { |
| registerSimpleClassAccessInEnvir(arg, valueNode); |
| if (slot != null) { |
| slot.completeType(valueNode.getText()); |
| } |
| SourceAnalyzer.this.argValueToIgnore.add(valueNode); |
| } |
| } |
| } |
| else { // superclasses (like setClass arg contains) |
| final RAstNode valueNode= arg.getValueChild(); |
| if (valueNode != null) { |
| if (valueNode.getNodeType() == NodeType.STRING_CONST) { |
| registerSimpleClassAccessInEnvir(arg, valueNode); |
| if (containerBuilder != null) { |
| superClassNames[i]= valueNode.getText(); |
| } |
| SourceAnalyzer.this.argValueToIgnore.add(valueNode); |
| } |
| } |
| } |
| } |
| if (containerBuilder != null) { |
| rClass.addSuperClasses(superClassNames); |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsPrototype implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| |
| public MethodsPrototype(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_PROTOTYPE_args; |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| final SourceElementBuilder containerBuilder= (SourceAnalyzer.this.request == PROTOTYPE_REQUEST) ? |
| getCurrentSourceContainerBuilder(RElement.R_S4CLASS) : null; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| |
| if (args.ellipsisArgs.length > 0) { |
| // final RSourceElementByElementAccess.RClass classDef= (containerBuilder != null) ? |
| // (RSourceElementByElementAccess.RClass)containerBuilder.element : null; |
| for (int i= 0; i < args.ellipsisArgs.length; i++) { |
| final FCall.Arg arg= args.ellipsisArgs[i]; |
| final RAstNode slotNameNode= arg.getNameChild(); |
| if (slotNameNode != null) { // slot |
| final String slotName= slotNameNode.getText(); |
| RSlot slot= null; |
| if (containerBuilder != null && slotName != null) { |
| final ElementAccess.Slot access= new ElementAccess.Slot(arg); |
| access.flags= ElementAccess.A_WRITE; |
| access.nameNode= slotNameNode; |
| containerBuilder.envir.addRunResolve(slotName, access); |
| for (final RSourceElementByElementAccess child : containerBuilder.children) { |
| if (child.getElementType() == RElement.R_S4SLOT |
| && slotName.equals(child.getElementName().getSegmentName()) ) { |
| slot= (RSlot)child; |
| break; |
| } |
| } |
| } |
| if (arg.hasValue()) { |
| // final RAstNode valueNode= arg.getValueChild(); |
| // if (slot != null) { |
| // slot.fPrototypeCode= value.toString(); |
| // } |
| } |
| } |
| // else { // data |
| // } |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsSetIs implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| private final int argIdx_classToExtendName; |
| private final int argIdx_testF; |
| private final int argIdx_coerceF; |
| private final int argIdx_replaceF; |
| |
| public MethodsSetIs(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETIS_args; |
| this.argIdx_className= this.argsDef.indexOf("class1"); |
| this.argIdx_classToExtendName= this.argsDef.indexOf("class2"); |
| this.argIdx_testF= this.argsDef.indexOf("test"); |
| this.argIdx_coerceF= this.argsDef.indexOf("coerce"); |
| this.argIdx_replaceF= this.argsDef.indexOf("replace"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode classNameNode= args.getArgValueNode(this.argIdx_className); |
| final RAstNode cToExtendNameNode= args.getArgValueNode(this.argIdx_classToExtendName); |
| RClassExt rClassExt= null; |
| BuildSourceFrame envir= null; |
| |
| String extTypeName= null; |
| if (classNameNode != null && classNameNode.getNodeType() == NodeType.STRING_CONST) { |
| extTypeName= classNameNode.getText(); |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_WRITE; |
| access.nameNode= classNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(extTypeName, access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(classNameNode); |
| |
| envir= new BuildSourceFrame.RunScope(RFrame.FUNCTION, |
| BuildSourceFrame.createId(RFrame.FUNCTION, access.getSegmentName(), ++SourceAnalyzer.this.anonymCount), |
| SourceAnalyzer.this.topScope ); |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| rClassExt= new RClassExt(containerBuilder.element, access, envir, "setIs"); |
| registerClassExtElement(rClassExt); |
| } |
| else { |
| node.addAttachment(envir); |
| } |
| } |
| if (cToExtendNameNode != null && cToExtendNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= cToExtendNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(cToExtendNameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(cToExtendNameNode); |
| |
| if (rClassExt != null) { |
| rClassExt.complete(extTypeName); |
| } |
| } |
| |
| if (rClassExt != null) { |
| enterElement(rClassExt, envir, node); |
| |
| visitAndCheckValue(args.allocatedArgs[this.argIdx_testF], "test"); |
| visitAndCheckValue(args.allocatedArgs[this.argIdx_coerceF], "coerce"); |
| visitAndCheckValue(args.allocatedArgs[this.argIdx_replaceF], "replace"); |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| |
| leaveElement(); |
| } |
| else { |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| } |
| SourceAnalyzer.this.returnValue= null; |
| return; |
| } |
| |
| } |
| |
| |
| protected final class MethodsRemoveClass implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| |
| public MethodsRemoveClass(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_REMOVECLASS_args; |
| this.argIdx_className= this.argsDef.indexOf("Class"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode classNameNode= args.getArgValueNode(this.argIdx_className); |
| |
| if (classNameNode != null && classNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_DELETE; |
| access.nameNode= classNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(classNameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(classNameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| return; |
| } |
| |
| } |
| |
| protected final class MethodsSetAs implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| private final int argIdx_toClass; |
| |
| public MethodsSetAs(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETAS_args; |
| this.argIdx_className= this.argsDef.indexOf("from"); |
| this.argIdx_toClass= this.argsDef.indexOf("to"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode classNameNode= args.getArgValueNode(this.argIdx_className); |
| final RAstNode toClassNode= args.getArgValueNode(this.argIdx_toClass); |
| |
| if (classNameNode != null && classNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_WRITE; |
| access.nameNode= classNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(classNameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(classNameNode); |
| } |
| if (toClassNode != null && toClassNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_READ; |
| access.nameNode= toClassNode; |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(toClassNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(toClassNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| return; |
| } |
| |
| } |
| |
| protected final class MethodsSetValidity implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| |
| public MethodsSetValidity(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETVALIDITY_args; |
| this.argIdx_className= this.argsDef.indexOf("Class"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode classNameNode= args.getArgValueNode(this.argIdx_className); |
| |
| if (classNameNode != null && classNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Class(node); |
| access.flags= ElementAccess.A_WRITE; |
| access.nameNode= classNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.addClass(classNameNode.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(classNameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| return; |
| } |
| |
| } |
| |
| private abstract class MethodsCommonClassRead implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_className; |
| |
| protected MethodsCommonClassRead(final ArgsDefinition argsDef, final String classNameNodeName) { |
| this.argsDef= argsDef; |
| this.argIdx_className= this.argsDef.indexOf(classNameNodeName); |
| } |
| |
| @Override |
| public final void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode classNameNode= args.getArgValueNode(this.argIdx_className); |
| |
| if (classNameNode != null && classNameNode.getNodeType() == NodeType.STRING_CONST) { |
| registerSimpleClassAccessInEnvir(node, classNameNode); |
| SourceAnalyzer.this.argValueToIgnore.add(classNameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsGetClass extends MethodsCommonClassRead { |
| |
| public MethodsGetClass(final RCoreFunctions rdef) { |
| super(rdef.METHODS_GETCLASS_args, "Class"); |
| } |
| |
| } |
| |
| protected final class MethodsGetClassDef extends MethodsCommonClassRead { |
| |
| public MethodsGetClassDef(final RCoreFunctions rdef) { |
| super(rdef.METHODS_GETCLASSDEF_args, "Class"); |
| } |
| |
| } |
| |
| protected final class MethodsFindClass extends MethodsCommonClassRead { |
| |
| public MethodsFindClass(final RCoreFunctions rdef) { |
| super(rdef.METHODS_FINDCLASS_args, "Class"); |
| } |
| |
| } |
| |
| protected final class MethodsNew extends MethodsCommonClassRead { |
| |
| public MethodsNew(final RCoreFunctions rdef) { |
| super(rdef.METHODS_NEW_args, "Class"); |
| } |
| |
| } |
| |
| protected final class MethodsAs extends MethodsCommonClassRead { |
| |
| public MethodsAs(final RCoreFunctions rdef) { |
| super(rdef.METHODS_AS_args, "Class"); |
| } |
| |
| } |
| |
| protected final class MethodsSetMethod implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| private final int argIdx_signature; |
| private final int argIdx_fDef; |
| |
| public MethodsSetMethod(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SETMETHOD_args; |
| this.argIdx_fName= this.argsDef.indexOf("f"); |
| this.argIdx_signature= this.argsDef.indexOf("signature"); |
| this.argIdx_fDef= this.argsDef.indexOf("definition"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode fNameValue= args.getArgValueNode(this.argIdx_fName); |
| final RAstNode fDefValue= args.getArgValueNode(this.argIdx_fDef); |
| |
| if (fNameValue != null && fNameValue.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE | ElementAccess.A_FUNC; |
| access.nameNode= fNameValue; |
| SourceAnalyzer.this.genericDefaultEnvir.add(fNameValue.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(fNameValue); |
| |
| final Signature sig= readSignature(node, args.getArgValueNode(this.argIdx_signature)); |
| final Object value= (fDefValue != null) ? evalArgValue(fDefValue, NO_REQUESTS) : null; |
| RMethod rMethod; |
| if (value instanceof RMethod) { |
| rMethod= (RMethod)value; |
| registerFunctionElement(rMethod, RElement.R_S4METHOD, access, sig); |
| } |
| else { |
| final BuildSourceFrame envir= new BuildSourceFrame.DefScope(RFrame.FUNCTION, |
| BuildSourceFrame.createId(RFrame.FUNCTION, access.getSegmentName(), ++SourceAnalyzer.this.anonymCount), |
| access.getSegmentName(), new BuildSourceFrame[] { SourceAnalyzer.this.topLevelEnvir } ); |
| final SourceElementBuilder containerBuilder= getCurrentSourceContainerBuilder(); |
| if (containerBuilder != null) { |
| rMethod= new RMethod(containerBuilder.element, RElement.R_S4METHOD, access, envir); |
| enterElement(rMethod, envir, node); |
| leaveElement(); |
| registerFunctionElement(rMethod, RElement.R_S4METHOD, access, sig); |
| } |
| else { |
| addEnvirInsteadOfElement(envir, node); |
| } |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsRemoveMethod implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| private final int argIdx_signature; |
| |
| public MethodsRemoveMethod(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_REMOVEMETHOD_args; |
| this.argIdx_fName= this.argsDef.indexOf("f"); |
| this.argIdx_signature= this.argsDef.indexOf("signature"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode fNameArg= args.getArgValueNode(this.argIdx_fName); |
| |
| if (fNameArg != null && fNameArg.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_DELETE | ElementAccess.A_FUNC; |
| access.nameNode= fNameArg; |
| SourceAnalyzer.this.genericDefaultEnvir.addLateResolve(fNameArg.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(fNameArg); |
| |
| // final Signature sig= readSignature(node, args.getArgValueNode(this.argIdx_signature)); |
| // this.returnValue= null; |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsRemoveMethods implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| |
| public MethodsRemoveMethods(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_REMOVEMETHODS_args; |
| this.argIdx_fName= this.argsDef.indexOf("f"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode fNameArg= args.getArgValueNode(this.argIdx_fName); |
| |
| if (fNameArg != null && fNameArg.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_DELETE | ElementAccess.A_FUNC; |
| access.nameNode= fNameArg; |
| SourceAnalyzer.this.genericDefaultEnvir.addLateResolve(fNameArg.getText(), access); |
| |
| SourceAnalyzer.this.argValueToIgnore.add(fNameArg); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| private class MethodsCommonMethodRead implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_fName; |
| |
| protected MethodsCommonMethodRead(final ArgsDefinition argsDef, final String fNameNodeName) { |
| this.argsDef= argsDef; |
| this.argIdx_fName= this.argsDef.indexOf(fNameNodeName); |
| } |
| |
| @Override |
| public final void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode fNameNode= args.getArgValueNode(this.argIdx_fName); |
| |
| if (fNameNode != null && fNameNode.getNodeType() == NodeType.STRING_CONST) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_READ | ElementAccess.A_FUNC; |
| access.nameNode= fNameNode; |
| SourceAnalyzer.this.genericDefaultEnvir.add(fNameNode.getText(), access); |
| SourceAnalyzer.this.argValueToIgnore.add(fNameNode); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| protected final class MethodsGetMethod extends MethodsCommonMethodRead { |
| |
| public MethodsGetMethod(final RCoreFunctions rdef) { |
| super(rdef.METHODS_GETMETHOD_args, "f"); |
| } |
| |
| } |
| |
| protected final class MethodsSelectMethod extends MethodsCommonMethodRead { |
| |
| public MethodsSelectMethod(final RCoreFunctions rdef) { |
| super(rdef.METHODS_SELECTMETHOD_args, "f"); |
| } |
| |
| } |
| |
| protected final class MethodsGetMethods extends MethodsCommonMethodRead { |
| |
| public MethodsGetMethods(final RCoreFunctions rdef) { |
| super(rdef.METHODS_GETMETHODS_args, "f"); |
| } |
| |
| } |
| |
| protected final class MethodsFindMethod extends MethodsCommonMethodRead { |
| |
| public MethodsFindMethod(final RCoreFunctions rdef) { |
| super(rdef.METHODS_FINDMETHOD_args, "f"); |
| } |
| |
| } |
| |
| protected final class MethodsSlot implements FCallAnalyzer { |
| |
| private final ArgsDefinition argsDef; |
| private final int argIdx_object; |
| private final int argIdx_slotName; |
| |
| |
| public MethodsSlot(final RCoreFunctions rdef) { |
| this.argsDef= rdef.METHODS_SLOT_args; |
| this.argIdx_object= this.argsDef.indexOf("object"); |
| this.argIdx_slotName= this.argsDef.indexOf("name"); |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| final FCallArgMatch args= RAsts.matchArgs(node.getArgsChild(), this.argsDef); |
| final RAstNode objectArg= args.getArgValueNode(this.argIdx_object); |
| final RAstNode slotArg= args.getArgValueNode(this.argIdx_slotName); |
| |
| if (objectArg != null && objectArg.getNodeType() == NodeType.SYMBOL) { |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= (assignment) ? |
| (ElementAccess.A_WRITE | ElementAccess.A_SUB) : |
| (ElementAccess.A_READ | ElementAccess.A_SUB); |
| access.nameNode= objectArg; |
| SourceAnalyzer.this.argValueToIgnore.add(objectArg); |
| |
| if (slotArg != null && slotArg.getNodeType() == NodeType.STRING_CONST) { |
| access.nextSegment= new SubNamedSlotSemanticElementAccess(access, slotArg); |
| SourceAnalyzer.this.argValueToIgnore.add(slotArg); |
| } |
| |
| SourceAnalyzer.this.topScope.addLateResolve(objectArg.getText(), access); |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| |
| protected final class NoDefFallback implements FCallAnalyzer { |
| |
| public NoDefFallback() { |
| } |
| |
| @Override |
| public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| SourceAnalyzer.this.request= NO_REQUESTS; |
| |
| final FCall.Args args= node.getArgsChild(); |
| if (args.getChildCount() > 0 && assignment) { |
| final FCall.Arg firstArg= args.getChild(0); |
| final RAstNode argName= firstArg.getNameChild(); |
| final RAstNode argValue= firstArg.getValueChild(); |
| if (argValue != null |
| && (argName == null || isTextEqualTo(argName, "x")) ) { //$NON-NLS-1$ |
| final ElementAccess access= new ElementAccess.Default(node); |
| access.flags= ElementAccess.A_WRITE; |
| final String mainName= resolveElementName(argValue, access, false); |
| SourceAnalyzer.this.argValueToIgnore.add(argValue); |
| if (mainName != null) { |
| registerInEnvir(S_SEARCH, mainName, access); |
| } |
| } |
| } |
| |
| node.getArgsChild().acceptInRChildren(SourceAnalyzer.this); |
| SourceAnalyzer.this.returnValue= null; |
| } |
| |
| } |
| |
| // protected final class Template1 implements IFCallAnalyzer { |
| // |
| // public Template1(final RCoreFunctions rdef) { |
| // } |
| // |
| // public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| // } |
| // |
| // } |
| |
| // protected final class Template2 implements IFCallAnalyzer { |
| // |
| // private final ArgsDefinition argsDef; |
| // |
| // public Template2(final RCoreFunctions rdef) { |
| // this.argsDef= rdef.; |
| // } |
| // |
| // public void visit(final FCall node, final boolean assignment) throws InvocationTargetException { |
| // } |
| // |
| // } |
| |
| private @Nullable Signature readSignature(final RAstNode refNode, final @Nullable RAstNode sigValue) throws InvocationTargetException { |
| if (sigValue != null) { |
| final Object value= evalArgValue(sigValue, SIGNATURE_REQUESTS); |
| if (value instanceof ReturnValue) { |
| final ReturnValue returnValue= (ReturnValue)value; |
| if (returnValue.returnType == RETURN_METHOD_SIGNATURE) { |
| return (Signature)returnValue; |
| } |
| if (returnValue.returnType == RETURN_STRING_ARRAY) { |
| final RAstNode[] nodes= ((NodeArray)returnValue).array; |
| final @Nullable String[] classNames= new @Nullable String[nodes.length]; |
| for (int i= 0; i < nodes.length; i++) { |
| registerSimpleClassAccessInEnvir(refNode, nodes[i]); |
| classNames[i]= nodes[i].getText(); |
| } |
| return new Signature(null, classNames); |
| } |
| } |
| else { |
| return null; |
| } |
| } |
| return null; |
| } |
| |
| public static ArgsDefinition createMethodArgDef(final @Nullable FDef fdefNode, final @Nullable Signature sig) { |
| final FDef.Args argList= (fdefNode != null) ? fdefNode.getArgsChild() : null; |
| final ArgsBuilder b= new ArgsBuilder(); |
| if (argList != null) { |
| final int n= argList.getChildCount(); |
| if (sig != null && sig.classNames != null) { |
| ITER_ARGS: for (int i= 0; i < n; i++) { |
| final String argName= argList.getChild(i).getNameChild().getText(); |
| final @Nullable ElementAccess[] argNameAccesses; |
| if (argName != null && (argNameAccesses= sig.argNameAccesses) != null) { |
| for (int j= 0; j < argNameAccesses.length; j++) { |
| final ElementAccess argNameAccess= argNameAccesses[j]; |
| final RAstNode nameNode; |
| if (argNameAccess != null && (nameNode= argNameAccess.nameNode) != null |
| && isTextEqualTo(nameNode, argName) ) { |
| b.add(argName, 0, sig.classNames[j]); |
| continue ITER_ARGS; |
| } |
| } |
| continue ITER_ARGS; |
| } |
| else if (i < sig.classNames.length) { |
| b.add(argName, 0, sig.classNames[i]); |
| continue ITER_ARGS; |
| } |
| else { |
| b.add(argName, 0, null); |
| continue ITER_ARGS; |
| } |
| } |
| } |
| else { // (sig == null || sigClasses == null) |
| ITER_ARGS: for (int i= 0; i < n; i++) { |
| final String argName= argList.getChild(i).getNameChild().getText(); |
| b.add(argName, 0, null); |
| continue ITER_ARGS; |
| } |
| } |
| } |
| else { // (argList == null) |
| final @Nullable ElementAccess[] argNameAccesses; |
| if (sig != null && (argNameAccesses= sig.argNameAccesses) != null && sig.classNames != null) { |
| ITER_ARGS: for (int i= 0; i < argNameAccesses.length; i++) { |
| final ElementAccess argNameAccess= argNameAccesses[i]; |
| final RAstNode nameNode; |
| if (argNameAccess != null && (nameNode= argNameAccess.nameNode) != null) { |
| b.add(nameNode.getText(), 0, sig.classNames[i]); |
| continue ITER_ARGS; |
| } |
| else { |
| break ITER_ARGS; |
| } |
| } |
| } |
| } |
| return b.build(); |
| } |
| |
| private BuildSourceFrame readScopeArgs(final @Nullable RAstNode pos, final BuildSourceFrame defaultScope) throws InvocationTargetException { |
| this.returnValue= null; |
| BuildSourceFrame envir= null; |
| if (pos != null) { |
| switch (pos.getNodeType()) { |
| case NUM_CONST: |
| { final Integer javaInt= RAsts.toJavaInt(pos, false); |
| if (javaInt != null && javaInt.intValue() == 1) { // search pos |
| envir= this.globalEnvir; |
| break; |
| } |
| } |
| break; |
| case STRING_CONST: // search name |
| { final String text= pos.getText(); |
| if (text != null) { |
| if (text.equals(".GlobalEnv")) { |
| envir= this.globalEnvir; |
| break; |
| } |
| if (text.startsWith("package:")) { |
| envir= getPkgEnvir(text.substring(8)); |
| break; |
| } |
| } |
| } |
| break; |
| default: |
| // check for environment |
| pos.acceptInR(SourceAnalyzer.this); |
| if (this.returnValue instanceof BuildSourceFrame) { |
| envir= (BuildSourceFrame) this.returnValue; |
| break; |
| } |
| break; |
| } |
| this.argValueToIgnore.add(pos); |
| } |
| if (envir != null) { |
| return envir; |
| } |
| return defaultScope; |
| } |
| |
| } |