/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.tvl.goworks.editor.go.parser;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.antlr.netbeans.editor.text.DocumentSnapshot;
import org.antlr.v4.runtime.Dependents;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.RuleDependencies;
import org.antlr.v4.runtime.RuleDependency;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.RuleNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.tvl.goworks.editor.go.codemodel.ChannelKind;
import org.tvl.goworks.editor.go.codemodel.FunctionModel;
import org.tvl.goworks.editor.go.codemodel.IntrinsicTypeModels;
import org.tvl.goworks.editor.go.codemodel.VarKind;
import org.tvl.goworks.editor.go.codemodel.impl.ConstModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.FieldModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.FileModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.FunctionModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.ImportDeclarationModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.PackageDeclarationModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.ParameterModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeAliasModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeArrayModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeChannelModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeFunctionModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeInterfaceModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeMapModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypePointerModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeReferenceModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeSliceModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.TypeStructModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.VarModelImpl;
import org.tvl.goworks.editor.go.codemodel.impl.VariadicParameterSliceModelImpl;
import org.tvl.goworks.editor.go.completion.GoCompletionQuery;
import org.tvl.goworks.editor.go.highlighter.SemanticHighlighter;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.AndExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.AnonymousFieldContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ArrayTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.BaseTypeNameContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.BasicLiteralContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.BodyContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.BuiltinArgsContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.BuiltinCallContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.BuiltinCallExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ChannelTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.CompareExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.CompositeLiteralContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ConstSpecContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ConversionContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ConversionOrCallExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ExpressionContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ExpressionListContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.FieldDeclContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.FunctionDeclContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.FunctionLiteralContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.FunctionTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.IdentifierListContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ImportSpecContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.InterfaceTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.InterfaceTypeNameContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.LiteralContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.MapTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.MethodDeclContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.MethodExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.MethodSpecContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.OperandContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.OperandExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.OrExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.PackageClauseContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.PackageNameContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ParameterDeclContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.PointerTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.QualifiedIdentifierContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ReceiverContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.ResultContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.SliceTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.SourceFileBodyContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.StructTypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.TypeAssertionExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.TypeContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.TypeListContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.TypeLiteralContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.TypeNameContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.TypeSpecContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.UnaryExprContext;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.VarSpecContext;
import org.tvl.goworks.editor.go.parser.generated.GoParserBaseListener;
import org.tvl.goworks.project.GoProject;
/**
*
* @author Sam Harwell
*/
public class CodeModelBuilderListener extends GoParserBaseListener {
// -J-Dorg.tvl.goworks.editor.go.parser.CodeModelBuilderListener.level=FINE
private static final Logger LOGGER = Logger.getLogger(CodeModelBuilderListener.class.getName());
public static final ParseTreeWalker PARSE_TREE_WALKER = new ParseTreeWalker() {
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_body, version=0)
public void walk(ParseTreeListener listener, ParseTree t) {
if (t instanceof RuleNode) {
RuleNode ruleNode = (RuleNode)t;
if (ruleNode.getRuleContext() instanceof BodyContext) {
return;
}
}
super.walk(listener, t);
}
};
private final GoProject _project;
private final DocumentSnapshot _snapshot;
private final Token[] _tokens;
private FileModelImpl _fileModel;
private TypeModelImpl _unknownType;
/**
* This is always balanced in {@link #enterStructType} and
* {@link #exitStructType}.
*/
private final Deque<TypeStructModelImpl> _structModelStack = new ArrayDeque<>();
/**
* This is always balanced in {@link #enterInterfaceType} and
* {@link #exitInterfaceType}.
*/
private final Deque<TypeInterfaceModelImpl> _interfaceModelStack = new ArrayDeque<>();
/**
* This is always balanced in {@link #enterInterfaceType} and
* {@link #exitInterfaceType}.
*/
private final Deque<Collection<TypeModelImpl>> _implementedTypesContainerStack = new ArrayDeque<>();
/**
* This is always balanced in {@link #enterSourceFileBody} and
* {@link #exitSourceFileBody}.
*/
private final Deque<Collection<TypeModelImpl>> _typeContainerStack = new ArrayDeque<>();
/**
* This is always balanced in {@link #enterSourceFileBody} and
* {@link #exitSourceFileBody}.
*/
private final Deque<Collection<ConstModelImpl>> _constContainerStack = new ArrayDeque<>();
/**
* This is always balanced in {@link #enterSourceFileBody} and
* {@link #exitSourceFileBody}.
*/
private final Deque<Collection<VarModelImpl>> _varContainerStack = new ArrayDeque<>();
/**
* This is always balanced in {@link #enterSourceFileBody} and
* {@link #exitSourceFileBody}, and in {@link #enterInterfaceType} and
* {@link #exitInterfaceType}.
*/
private final Deque<Collection<FunctionModelImpl>> _functionContainerStack = new ArrayDeque<>();
/**
* This is always balanced in the following pairs of methods:
* <ul>
* <li>{@link #enterFunctionType} and {@link #exitFunctionType}</li>
* <li>{@link #enterMethodDecl} and {@link #exitMethodDecl}</li>
* <li>{@link #enterMethodSpec} and {@link #exitMethodSpec}</li>
* <li>{@link #enterFunctionDecl} and {@link #exitFunctionDecl}</li>
* <li>{@link #enterResult} (balanced within this single method)</li>
* </ul>
*/
private final Deque<Collection<ParameterModelImpl>> _parameterContainerStack = new ArrayDeque<>();
/**
* This is always balanced in the following pairs of methods:
* <ul>
* <li>{@link #enterFunctionType} and {@link #exitFunctionType}</li>
* <li>{@link #enterMethodDecl} and {@link #exitMethodDecl}</li>
* <li>{@link #enterMethodSpec} and {@link #exitMethodSpec}</li>
* <li>{@link #enterFunctionDecl} and {@link #exitFunctionDecl}</li>
* </ul>
*/
private final Deque<FunctionModel> _functionModelStack = new ArrayDeque<>();
/**
* This stack is implicitly balanced.
*/
private final Deque<TypeModelImpl> _typeModelStack = new ArrayDeque<>();
private final Map<ParserRuleContext, TypeModelImpl> _expressionTypes = new HashMap<>();
public CodeModelBuilderListener(DocumentSnapshot snapshot, Token[] tokens) {
Project project = FileOwnerQuery.getOwner(snapshot.getVersionedDocument().getFileObject());
if (!(project instanceof GoProject)) {
throw new UnsupportedOperationException("Unsupported project type.");
}
this._project = (GoProject)project;
this._snapshot = snapshot;
this._tokens = tokens;
}
public FileModelImpl getFileModel() {
return _fileModel;
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_sourceFileBody, version=1)
public void enterSourceFileBody(SourceFileBodyContext ctx) {
FileObject documentFileObject = _snapshot.getVersionedDocument().getFileObject();
FileObject packageFolder = documentFileObject != null ? documentFileObject.getParent() : null;
FileObject sourceRoot = _project != null ? _project.getSourceRoot() : null;
String packagePath;
if (sourceRoot != null) {
packagePath = FileUtil.getRelativePath(sourceRoot, packageFolder);
if (packagePath == null) {
LOGGER.log(Level.WARNING, "Found source file in unexpected folder ''{0}'', which is not under the source root ''{1}''.", new Object[] { packageFolder, sourceRoot });
packagePath = FileUtil.getRelativePath(_project.getProjectDirectory(), packageFolder);
}
assert packagePath != null;
} else {
packagePath = packageFolder.getNameExt();
}
FileObject fileObject = _snapshot.getVersionedDocument().getFileObject();
this._fileModel = new FileModelImpl(fileObject, _project, packagePath);
this._typeContainerStack.push(this._fileModel.getTypes());
this._constContainerStack.push(this._fileModel.getConstants());
this._varContainerStack.push(this._fileModel.getVars());
this._functionContainerStack.push(this._fileModel.getFunctions());
this._unknownType = new GoCompletionQuery.UnknownTypeModelImpl(_fileModel);
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_sourceFileBody, version=1)
public void exitSourceFileBody(SourceFileBodyContext ctx) {
this._fileModel.freeze();
this._typeContainerStack.pop();
this._constContainerStack.pop();
this._varContainerStack.pop();
this._functionContainerStack.pop();
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_packageClause, version=0),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_packageName, version=0),
})
public void exitPackageClause(PackageClauseContext ctx) {
PackageNameContext nameContext = ctx.packageName();
if (nameContext != null && nameContext.IDENTIFIER() != null) {
String name = nameContext.IDENTIFIER().getSymbol().getText();
PackageDeclarationModelImpl model = new PackageDeclarationModelImpl(name, _project, nameContext.IDENTIFIER(), nameContext);
_fileModel.getPackageDeclarations().add(model);
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_importSpec, version=0),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_importPath, version=0),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_packageName, version=0),
})
public void exitImportSpec(ImportSpecContext ctx) {
if (ctx.importPath() == null || ctx.importPath().StringLiteral() == null) {
return;
}
String path = ctx.importPath().StringLiteral().getSymbol().getText();
path = path.substring(1, path.length() - 1);
String alias;
if (ctx.dot != null) {
alias = ".";
} else if (ctx.packageName() != null && ctx.packageName().IDENTIFIER() != null) {
alias = ctx.packageName().IDENTIFIER().getSymbol().getText();
} else {
alias = GoParser.getPackageName(ctx.importPath().StringLiteral().getSymbol());
}
ImportDeclarationModelImpl model = new ImportDeclarationModelImpl(path, alias, ctx.dot != null, _fileModel, ctx);
_fileModel.getImportDeclarations().add(model);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=2, dependents={Dependents.PARENTS, Dependents.SELF}),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeName, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeLiteral, version=0, dependents=Dependents.SELF),
})
public void exitType(TypeContext ctx) {
TypeModelImpl type = popTypeModel(ctx.typeName(), ctx.typeLiteral(), ctx.type());
_typeModelStack.push(type);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeName, version=3, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_qualifiedIdentifier, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_packageName, version=0, dependents=Dependents.SELF),
})
public void exitTypeName(TypeNameContext ctx) {
QualifiedIdentifierContext qualifiedIdentifierContext = ctx.qualifiedIdentifier();
PackageNameContext packageNameContext = qualifiedIdentifierContext != null ? qualifiedIdentifierContext.packageName() : null;
TerminalNode packageName = packageNameContext != null ? packageNameContext.IDENTIFIER() : null;
String pkgName = packageName != null ? packageName.getSymbol().getText() : null;
String typeName;
if (qualifiedIdentifierContext != null && qualifiedIdentifierContext.IDENTIFIER() != null) {
typeName = qualifiedIdentifierContext.IDENTIFIER().getSymbol().getText();
} else {
typeName = "?";
}
_typeModelStack.push(new TypeReferenceModelImpl(pkgName, typeName, _fileModel));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeLiteral, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_arrayType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_structType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_pointerType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_interfaceType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_sliceType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_mapType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_channelType, version=0, dependents=Dependents.SELF),
})
public void exitTypeLiteral(TypeLiteralContext ctx) {
@NonNull
TypeModelImpl result = _unknownType;
if (ctx.getChildCount() > 0) {
ParseTree child = ctx.getChild(0);
if (child instanceof RuleNode) {
RuleContext ruleContext = ((RuleNode)child).getRuleContext();
switch (ruleContext.getRuleIndex()) {
case GoParser.RULE_arrayType:
case GoParser.RULE_structType:
case GoParser.RULE_pointerType:
case GoParser.RULE_functionType:
case GoParser.RULE_interfaceType:
case GoParser.RULE_sliceType:
case GoParser.RULE_mapType:
case GoParser.RULE_channelType:
result = popTypeModel((ParserRuleContext)ruleContext);
break;
default:
break;
}
}
}
_typeModelStack.push(result);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_interfaceTypeName, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeName, version=0, dependents=Dependents.SELF),
})
public void exitInterfaceTypeName(InterfaceTypeNameContext ctx) {
_typeModelStack.push(popTypeModel(ctx.typeName()));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_arrayType, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_elementType, version=0, dependents=Dependents.SELF),
})
public void exitArrayType(ArrayTypeContext ctx) {
TypeModelImpl elementType = popTypeModel(ctx.elementType());
_typeModelStack.push(new TypeArrayModelImpl(elementType));
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_structType, version=0, dependents=Dependents.PARENTS)
public void enterStructType(StructTypeContext ctx) {
String typeName = createAnonymousTypeName(ctx);
_structModelStack.push(new TypeStructModelImpl(typeName, _fileModel, ctx));
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_structType, version=0, dependents=Dependents.PARENTS)
public void exitStructType(StructTypeContext ctx) {
_typeModelStack.push(_structModelStack.pop());
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_pointerType, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_baseType, version=0, dependents=Dependents.SELF),
})
public void exitPointerType(PointerTypeContext ctx) {
TypeModelImpl elementType = popTypeModel(ctx.baseType());
_typeModelStack.push(new TypePointerModelImpl(elementType));
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionType, version=0, dependents=Dependents.PARENTS)
public void enterFunctionType(FunctionTypeContext ctx) {
String typeName = createAnonymousTypeName(ctx);
_functionModelStack.push(new TypeFunctionModelImpl(typeName, _fileModel, ctx));
_parameterContainerStack.push(new ArrayList<ParameterModelImpl>());
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionType, version=0, dependents=Dependents.PARENTS)
public void exitFunctionType(FunctionTypeContext ctx) {
_parameterContainerStack.pop();
_typeModelStack.push((TypeFunctionModelImpl)_functionModelStack.pop());
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_interfaceType, version=0, dependents=Dependents.PARENTS)
public void enterInterfaceType(InterfaceTypeContext ctx) {
String typeName = createAnonymousTypeName(ctx);
_interfaceModelStack.push(new TypeInterfaceModelImpl(typeName, _fileModel, ctx));
_implementedTypesContainerStack.push(_interfaceModelStack.peek().getImplementedInterfaces());
_functionContainerStack.push(_interfaceModelStack.peek().getInterfaceMethods());
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_interfaceType, version=0, dependents=Dependents.PARENTS)
public void exitInterfaceType(InterfaceTypeContext ctx) {
_typeModelStack.push(_interfaceModelStack.pop());
_implementedTypesContainerStack.pop();
_functionContainerStack.pop();
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_sliceType, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_elementType, version=0, dependents=Dependents.SELF),
})
public void exitSliceType(SliceTypeContext ctx) {
TypeModelImpl elementType = popTypeModel(ctx.elementType());
_typeModelStack.push(new TypeSliceModelImpl(elementType));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_mapType, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_keyType, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_elementType, version=0, dependents=Dependents.SELF),
})
public void exitMapType(MapTypeContext ctx) {
TypeModelImpl valueType = popTypeModel(ctx.elementType());
TypeModelImpl keyType = popTypeModel(ctx.keyType());
_typeModelStack.push(new TypeMapModelImpl(keyType, valueType));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_channelType, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_elementType, version=0, dependents=Dependents.SELF),
})
public void exitChannelType(ChannelTypeContext ctx) {
TypeModelImpl elementType = popTypeModel(ctx.elementType());
ChannelKind channelKind = ChannelKind.SendReceive;
if (ctx.send != null) {
channelKind = ChannelKind.Send;
} else if (ctx.recv != null) {
channelKind = ChannelKind.Receive;
}
_typeModelStack.push(new TypeChannelModelImpl(elementType, channelKind));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeSpec, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitTypeSpec(TypeSpecContext ctx) {
String name = "?";
if (ctx.IDENTIFIER() != null) {
name = ctx.IDENTIFIER().getSymbol().getText();
}
TypeModelImpl type = popTypeModel(ctx.type());
TypeModelImpl model = new TypeAliasModelImpl(name, type, _fileModel, ctx.IDENTIFIER(), ctx);
_typeContainerStack.peek().add(model);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_constSpec, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_identifierList, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expressionList, version=1, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitConstSpec(ConstSpecContext ctx) {
TypeModelImpl type = popTypeModel(ctx.type(), null);
IdentifierListContext idList = ctx.identifierList();
ExpressionListContext expressionList = ctx.expressionList();
List<? extends TerminalNode> ids = idList != null ? idList.IDENTIFIER() : Collections.<TerminalNode>emptyList();
List<? extends ExpressionContext> expressions = expressionList != null ? expressionList.expression() : Collections.<ExpressionContext>emptyList();
for (int i = 0; i < ids.size(); i++) {
TerminalNode id = ids.get(i);
String unevaluatedValue;
if (expressions.size() > i) {
unevaluatedValue = expressions.get(i).getText();
} else {
unevaluatedValue = null;
}
String evaluatedValue = null;
ConstModelImpl model = new ConstModelImpl(id.getSymbol().getText(), _fileModel, unevaluatedValue, evaluatedValue, type, id, ctx);
_constContainerStack.peek().add(model);
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_varSpec, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_identifierList, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expressionList, version=1, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=0, dependents=Dependents.SELF),
})
public void exitVarSpec(VarSpecContext ctx) {
TypeModelImpl explicitType = popTypeModel(ctx.type());
IdentifierListContext idList = ctx.identifierList();
ExpressionListContext expressionList = ctx.expressionList();
List<? extends TerminalNode> ids = idList != null ? idList.IDENTIFIER() : Collections.<TerminalNode>emptyList();
List<? extends ExpressionContext> expressions = expressionList != null ? expressionList.expression() : Collections.<ExpressionContext>emptyList();
boolean isGlobal = !ids.isEmpty() && _varContainerStack.peek() == _fileModel.getVars();
for (int i = 0; i < ids.size(); i++) {
TerminalNode id = ids.get(i);
TypeModelImpl varType = _unknownType;
if (ctx.type() != null) {
varType = explicitType;
} else if (i < expressions.size()) {
varType = getExpressionType(expressions.get(i));
}
VarModelImpl model = new VarModelImpl(id.getSymbol().getText(), isGlobal ? VarKind.GLOBAL : VarKind.LOCAL, varType, _fileModel, id, ctx);
_varContainerStack.peek().add(model);
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodDecl, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodName, version=0, dependents=Dependents.SELF),
})
public void enterMethodDecl(MethodDeclContext ctx) {
TerminalNode nameNode = ctx.methodName() != null ? ctx.methodName().IDENTIFIER() : null;
String name = nameNode != null ? nameNode.getSymbol().getText() : createAnonymousTypeName(ctx);
FunctionModelImpl model = new FunctionModelImpl(name, _fileModel, nameNode, ctx);
_functionContainerStack.peek().add(model);
_functionModelStack.push(model);
_parameterContainerStack.push(model.getParameters());
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodDecl, version=0, dependents=Dependents.PARENTS)
public void exitMethodDecl(MethodDeclContext ctx) {
_functionModelStack.pop();
_parameterContainerStack.pop();
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodSpec, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodName, version=0, dependents=Dependents.SELF),
})
public void enterMethodSpec(MethodSpecContext ctx) {
if (ctx.methodName() != null) {
TerminalNode nameNode = ctx.methodName().IDENTIFIER();
FunctionModelImpl model = new FunctionModelImpl(nameNode.getSymbol().getText(), _fileModel, nameNode, ctx);
_functionContainerStack.peek().add(model);
_functionModelStack.push(model);
_parameterContainerStack.push(model.getParameters());
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodSpec, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodName, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_interfaceTypeName, version=0, dependents=Dependents.SELF),
})
public void exitMethodSpec(MethodSpecContext ctx) {
if (ctx.methodName() != null) {
_functionModelStack.pop();
_parameterContainerStack.pop();
} else if (ctx.interfaceTypeName() != null) {
_implementedTypesContainerStack.peek().add(popTypeModel(ctx.interfaceTypeName()));
}
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_baseTypeName, version=0, dependents=Dependents.PARENTS)
public void exitBaseTypeName(BaseTypeNameContext ctx) {
String pkgName = null;
String typeName;
if (ctx.IDENTIFIER() != null) {
typeName = ctx.IDENTIFIER().getSymbol().getText();
} else {
typeName = "?";
}
_typeModelStack.push(new TypeReferenceModelImpl(pkgName, typeName, _fileModel));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_receiver, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_baseTypeName, version=0, dependents=Dependents.SELF),
})
public void exitReceiver(ReceiverContext ctx) {
TerminalNode nameNode = ctx.IDENTIFIER();
String name = nameNode != null ? nameNode.getSymbol().getText() : "_";
if (ctx.baseTypeName() != null) {
TypeModelImpl type = popTypeModel(ctx.baseTypeName());
if (ctx.ptr != null) {
type = new TypePointerModelImpl(type);
}
ParameterModelImpl receiver = new ParameterModelImpl(name, VarKind.RECEIVER, type, _fileModel, nameNode, ctx);
((FunctionModelImpl)_functionModelStack.peek()).setReceiverParameter(receiver);
}
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionDecl, version=0, dependents=Dependents.PARENTS)
public void enterFunctionDecl(FunctionDeclContext ctx) {
TerminalNode nameNode = ctx.IDENTIFIER();
String name = nameNode != null ? nameNode.getText() : "?";
FunctionModelImpl model = new FunctionModelImpl(name, _fileModel, nameNode, ctx);
if (nameNode != null) {
_functionContainerStack.peek().add(model);
}
_functionModelStack.push(model);
_parameterContainerStack.push(model.getParameters());
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionDecl, version=0, dependents=Dependents.PARENTS)
public void exitFunctionDecl(FunctionDeclContext ctx) {
_functionModelStack.pop();
_parameterContainerStack.pop();
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_result, version=0, dependents=Dependents.PARENTS)
public void enterResult(ResultContext ctx) {
_parameterContainerStack.pop();
FunctionModel functionModel = _functionModelStack.peek();
Collection<ParameterModelImpl> returnValues;
if (functionModel instanceof FunctionModelImpl) {
returnValues = ((FunctionModelImpl)functionModel).getReturnValues();
} else {
returnValues = ((TypeFunctionModelImpl)functionModel).getReturnValues();
}
_parameterContainerStack.push(returnValues);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_result, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitResult(ResultContext ctx) {
if (ctx.type() != null) {
_parameterContainerStack.peek().add(new ParameterModelImpl("_", VarKind.RETURN, popTypeModel(ctx.type()), _fileModel, null, ctx));
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_parameterDecl, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_identifierList, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitParameterDecl(ParameterDeclContext ctx) {
if (ctx.identifierList() == null && ctx.type() == null) {
return;
}
TypeModelImpl parameterType = popTypeModel(ctx.type());
if (ctx.ellip != null) {
parameterType = new VariadicParameterSliceModelImpl(parameterType);
}
boolean isReturnParameter = _functionModelStack.peek().getReturnValues() == _parameterContainerStack.peek();
if (ctx.identifierList() != null) {
for (TerminalNode id : ctx.identifierList().IDENTIFIER()) {
_parameterContainerStack.peek().add(new ParameterModelImpl(id.getSymbol().getText(), isReturnParameter ? VarKind.RETURN : VarKind.PARAMETER, parameterType, _fileModel, id, ctx));
}
} else {
_parameterContainerStack.peek().add(new ParameterModelImpl("_", isReturnParameter ? VarKind.RETURN : VarKind.PARAMETER, parameterType, _fileModel, null, ctx));
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_fieldDecl, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_anonymousField, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_identifierList, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeName, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_qualifiedIdentifier, version=0, dependents=Dependents.SELF),
})
public void exitFieldDecl(FieldDeclContext ctx) {
TypeModelImpl fieldType = popTypeModel(ctx.type(), ctx.anonymousField());
IdentifierListContext idList = ctx.identifierList();
List<? extends TerminalNode> ids = idList != null ? idList.IDENTIFIER() : Collections.<TerminalNode>emptyList();
if (ctx.anonymousField() != null) {
AnonymousFieldContext anonymousFieldContext = ctx.anonymousField();
TypeNameContext typeNameContext = anonymousFieldContext != null ? anonymousFieldContext.typeName() : null;
QualifiedIdentifierContext qualifiedIdentifierContext = typeNameContext != null ? typeNameContext.qualifiedIdentifier() : null;
TerminalNode name = qualifiedIdentifierContext != null ? qualifiedIdentifierContext.IDENTIFIER() : null;
if (name != null) {
ids = Collections.singletonList(name);
}
}
for (TerminalNode id : ids) {
FieldModelImpl model = new FieldModelImpl(id.getSymbol().getText(), fieldType, ctx.anonymousField() != null, _fileModel, id, ctx);
_structModelStack.peek().getFields().add(model);
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitTypeAssertionExpr(TypeAssertionExprContext ctx) {
popTypeModel(ctx.type());
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodExpr, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_receiverType, version=3, dependents=Dependents.SELF),
})
public void exitMethodExpr(MethodExprContext ctx) {
popTypeModel(ctx.receiverType());
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_conversion, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitConversion(ConversionContext ctx) {
TypeModelImpl type = popTypeModel(ctx.type());
putExpressionType(ctx, type);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_conversion, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeName, version=0, dependents=Dependents.SELF),
})
public void exitConversionOrCallExpr(ConversionOrCallExprContext ctx) {
TypeModelImpl type = getExpressionType(ctx.conversion());
if (type != _unknownType) {
ConversionContext conversionContext = ctx.conversion();
TypeContext typeContext = conversionContext.type();
if (typeContext != null && typeContext.typeName() != null) {
if (!SemanticHighlighter.PREDEFINED_TYPES.contains(typeContext.typeName().getText())) {
LOGGER.log(Level.FINE, "{0}: Cannot distinguish conversion from call for type or method ''{1}''", new Object[] { _fileModel.getName(), typeContext.typeName().getText() });
type = _unknownType;
}
}
}
putExpressionType(ctx, type);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_builtinCall, version=0, dependents=Dependents.SELF),
})
public void exitBuiltinCallExpr(BuiltinCallExprContext ctx) {
putExpressionType(ctx, getExpressionType(ctx.builtinCall()));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_builtinCall, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_builtinArgs, version=2, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitBuiltinCall(BuiltinCallContext ctx) {
String functionName = ctx.IDENTIFIER() != null ? ctx.IDENTIFIER().getText() : null;
if (functionName == null || functionName.isEmpty()) {
return;
}
BuiltinArgsContext args = ctx.builtinArgs();
if (args == null) {
return;
}
switch (functionName) {
case "make":
putExpressionType(ctx, getExpressionType(args.type()));
break;
case "new":
putExpressionType(ctx, new TypePointerModelImpl(getExpressionType(args.type())));
break;
}
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents={Dependents.PARENTS, Dependents.SELF})
public void exitUnaryExpr(UnaryExprContext ctx) {
TypeModelImpl type = getExpressionType(ctx.expression());
if (ctx.op != null) {
switch (ctx.op.getType()) {
case GoLexer.Amp:
type = new TypePointerModelImpl(type);
break;
case GoLexer.Bang:
type = (TypeModelImpl)IntrinsicTypeModels.BOOL;
break;
case GoLexer.Caret:
case GoLexer.Plus:
case GoLexer.Minus:
// type unchanged
break;
case GoLexer.Star:
if (type instanceof TypePointerModelImpl) {
type = ((TypePointerModelImpl)type).getElementType();
} else {
LOGGER.log(Level.WARNING, "Unary operator '*' is currently only supported for trivial (non-aliased) pointer element types.");
return;
}
break;
default:
LOGGER.log(Level.WARNING, "Unsupported unary operator: {0}", ctx.op.getText());
return;
}
}
putExpressionType(ctx, type);
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS)
public void exitCompareExpr(CompareExprContext ctx) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.BOOL);
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS)
public void exitAndExpr(AndExprContext ctx) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.BOOL);
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS)
public void exitOrExpr(OrExprContext ctx) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.BOOL);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_builtinArgs, version=2, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitBuiltinArgs(BuiltinArgsContext ctx) {
TypeModelImpl type = popTypeModel(ctx.type());
putExpressionType(ctx, type);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_typeList, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_type, version=0, dependents=Dependents.SELF),
})
public void exitTypeList(TypeListContext ctx) {
for (TypeContext type : ctx.type()) {
popTypeModel(type);
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionLiteral, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionType, version=0, dependents=Dependents.SELF),
})
public void exitFunctionLiteral(FunctionLiteralContext ctx) {
TypeModelImpl type = popTypeModel(ctx.functionType());
putExpressionType(ctx, type);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_operand, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_literal, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_qualifiedIdentifier, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_methodExpr, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=0, dependents=Dependents.SELF),
})
public void exitOperand(OperandContext ctx) {
if (ctx.literal() != null) {
putExpressionType(ctx, getExpressionType(ctx.literal()));
} else if (ctx.qualifiedIdentifier()!= null) {
putExpressionType(ctx, getExpressionType(ctx.qualifiedIdentifier()));
} else if (ctx.methodExpr()!= null) {
putExpressionType(ctx, getExpressionType(ctx.methodExpr()));
} else if (ctx.expression()!= null) {
putExpressionType(ctx, getExpressionType(ctx.expression()));
}
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_expression, version=1, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_operand, version=0, dependents=Dependents.SELF),
})
public void exitOperandExpr(OperandExprContext ctx) {
putExpressionType(ctx, getExpressionType(ctx.operand()));
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_compositeLiteral, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_literalType, version=0, dependents=Dependents.SELF),
})
public void exitCompositeLiteral(CompositeLiteralContext ctx) {
TypeModelImpl type = popTypeModel(ctx.literalType());
putExpressionType(ctx, type);
}
@Override
@RuleDependencies({
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_literal, version=0, dependents=Dependents.PARENTS),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_basicLiteral, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_compositeLiteral, version=0, dependents=Dependents.SELF),
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_functionLiteral, version=0, dependents=Dependents.SELF),
})
public void exitLiteral(LiteralContext ctx) {
if (ctx.basicLiteral() != null) {
putExpressionType(ctx, getExpressionType(ctx.basicLiteral()));
} else if (ctx.compositeLiteral() != null) {
putExpressionType(ctx, getExpressionType(ctx.compositeLiteral()));
} else if (ctx.functionLiteral() != null) {
putExpressionType(ctx, getExpressionType(ctx.functionLiteral()));
}
}
@Override
@RuleDependency(recognizer=GoParser.class, rule=GoParser.RULE_basicLiteral, version=0, dependents=Dependents.PARENTS)
public void exitBasicLiteral(BasicLiteralContext ctx) {
if (ctx.INT_LITERAL() != null) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.INT);
} else if (ctx.FLOAT_LITERAL() != null) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.FLOAT64);
} else if (ctx.IMAGINARY_LITERAL() != null) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.COMPLEX128);
} else if (ctx.CharLiteral() != null) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.RUNE);
} else if (ctx.StringLiteral() != null) {
putExpressionType(ctx, (TypeModelImpl)IntrinsicTypeModels.STRING);
}
}
@NonNull
private TypeModelImpl getExpressionType(@NullAllowed ParserRuleContext context) {
if (context == null) {
return _unknownType;
}
TypeModelImpl result = _expressionTypes.get(context);
if (result == null) {
return _unknownType;
}
return result;
}
private void putExpressionType(@NonNull ParserRuleContext context, @NonNull TypeModelImpl type) {
if (type == _unknownType) {
return;
}
_expressionTypes.put(context, type);
}
@NonNull
private TypeModelImpl popTypeModel(@NullAllowed ParserRuleContext context) {
return popTypeModel(context, _unknownType);
}
@NonNull
private TypeModelImpl popTypeModel(@NullAllowed ParserRuleContext context, @NullAllowed TypeModelImpl defaultType) {
if (context != null) {
return _typeModelStack.pop();
}
return defaultType;
}
@NonNull
private TypeModelImpl popTypeModel(ParserRuleContext... contexts) {
int count = 0;
for (ParserRuleContext context : contexts) {
if (context != null) {
count++;
}
}
switch (count) {
case 0:
return _unknownType;
case 1:
return _typeModelStack.pop();
default:
throw new IllegalStateException();
}
}
@NonNull
private static String createAnonymousTypeName(@NonNull ParserRuleContext context) {
return String.format("$%s_%d", GoParser.ruleNames[context.getRuleIndex()], context.getStart().getStartIndex());
}
}