use of nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult in project magik-tools by StevenLooman.
the class MagikIndexer method handleDefinition.
private void handleDefinition(final MagikFile magikFile, final MethodDefinition definition) {
final AstNode node = definition.getNode();
if (node.isNot(MagikGrammar.METHOD_DEFINITION)) {
// No slot accessors, shared variables, shared constants.
this.handleMethodDefinitionOther(magikFile, definition);
return;
}
// Get exemplar.
final GlobalReference globalRef = definition.getTypeGlobalReference();
final AbstractType exemplarType = this.typeKeeper.getType(globalRef);
if (exemplarType == UndefinedType.INSTANCE) {
LOGGER.warn("Unknown type: {}", globalRef);
return;
}
// Combine parameter types with method docs.
final NewDocParser newDocParser = new NewDocParser(node);
final Map<String, String> parameterTypes = newDocParser.getParameterTypes();
final List<Parameter> parameters = definition.getParameters().stream().map(parameterDefinition -> {
final String name = parameterDefinition.getName();
final AbstractType type;
if (!parameterTypes.containsKey(name)) {
type = UndefinedType.INSTANCE;
} else {
final String parameterType = parameterTypes.get(name);
type = this.typeParser.parseTypeString(parameterType, globalRef.getPakkage());
}
final Parameter.Modifier modifier = MagikIndexer.PARAMETER_MODIFIER_MAPPING.get(parameterDefinition.getModifier());
return new Parameter(name, modifier, type);
}).collect(Collectors.toList());
final ParameterDefinition assignParamDef = definition.getAssignmentParameter();
final Parameter assignmentParameter = assignParamDef != null ? new Parameter(assignParamDef.getName(), MagikIndexer.PARAMETER_MODIFIER_MAPPING.get(assignParamDef.getModifier())) : null;
// Combine iterator types with method docs.
final ExpressionResult loopResult = newDocParser.getLoopTypes().stream().map(type -> this.typeParser.parseTypeString(type, globalRef.getPakkage())).collect(ExpressionResult.COLLECTOR);
// Combine return types with method docs.
final ExpressionResult callResult = newDocParser.getReturnTypes().stream().map(type -> this.typeParser.parseTypeString(type, globalRef.getPakkage())).collect(ExpressionResult.COLLECTOR);
// Create method.
final MagikType magikType = (MagikType) exemplarType;
final EnumSet<Method.Modifier> modifiers = definition.getModifiers().stream().map(modifier -> MagikIndexer.METHOD_MODIFIER_MAPPING.get(modifier)).collect(Collectors.toCollection(() -> EnumSet.noneOf(Method.Modifier.class)));
final URI uri = magikFile.getUri();
final Location location = new Location(uri, node);
final String methodName = definition.getMethodName();
final Method method = magikType.addMethod(modifiers, location, methodName, parameters, assignmentParameter, callResult, loopResult);
// Method doc.
final String methodDoc = MagikCommentExtractor.extractDocComments(node).map(Token::getValue).map(// Strip '##'
line -> line.substring(2)).collect(Collectors.joining("\n"));
method.setDoc(methodDoc);
// Save used types.
final AstNode bodyNode = node.getFirstChild(MagikGrammar.BODY);
final GlobalScope globalScope = magikFile.getGlobalScope();
final Scope bodyScope = globalScope.getScopeForNode(bodyNode);
Objects.requireNonNull(bodyScope);
bodyScope.getSelfAndDescendantScopes().stream().flatMap(scope -> scope.getScopeEntriesInScope().stream()).filter(scopeEntry -> scopeEntry.isType(ScopeEntry.Type.GLOBAL) || scopeEntry.isType(ScopeEntry.Type.DYNAMIC)).map(ScopeEntry::getIdentifier).map(identifier -> {
AbstractType type = this.typeKeeper.getType(globalRef);
if (type == UndefinedType.INSTANCE) {
return null;
} else if (type == SelfType.INSTANCE) {
// TODO: Does this actually happen?
type = this.typeKeeper.getType(globalRef);
}
return type;
}).filter(Objects::nonNull).forEach(method::addUsedType);
// Save called method names (thus without type).
node.getDescendants(MagikGrammar.METHOD_INVOCATION).stream().map(invocationNode -> {
final MethodInvocationNodeHelper invocationHelper = new MethodInvocationNodeHelper(invocationNode);
return invocationHelper.getMethodName();
}).forEach(method::addCalledMethod);
// Save used slot names.
node.getDescendants(MagikGrammar.SLOT).stream().map(slotNode -> slotNode.getFirstChild(MagikGrammar.IDENTIFIER).getTokenValue()).forEach(method::addUsedSlot);
final Path path = Paths.get(magikFile.getUri());
this.indexedMethods.get(path).add(method);
LOGGER.debug("Indexed method: {}", method);
}
use of nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult in project magik-tools by StevenLooman.
the class MagikIndexer method handleMethodDefinitionOther.
private void handleMethodDefinitionOther(final MagikFile magikFile, final MethodDefinition definition) {
// Slot accessors, shared variables, shared constants.
final GlobalReference globalRef = definition.getTypeGlobalReference();
final AbstractType exemplarType = this.typeKeeper.getType(globalRef);
if (exemplarType == UndefinedType.INSTANCE) {
LOGGER.warn("Unknown type: {}", globalRef);
return;
}
// Get method return types from docs, if any.
final AstNode node = definition.getNode();
final NewDocParser methodDocParser = new NewDocParser(node);
final List<AbstractType> methodReturnTypes = methodDocParser.getReturnTypes().stream().map(typeStr -> this.typeParser.parseTypeString(typeStr, globalRef.getPakkage())).collect(Collectors.toList());
// Get slot type from docs, if any.
final AstNode statementNode = node.getFirstAncestor(MagikGrammar.STATEMENT);
final AbstractType slotType;
if (statementNode != null) {
final NewDocParser exemplarDocParser = new NewDocParser(statementNode);
final String slotName = definition.getMethodName();
final String slotTypeStr = exemplarDocParser.getSlotTypes().get(slotName);
slotType = this.typeParser.parseTypeString(slotTypeStr, globalRef.getPakkage());
} else {
slotType = UndefinedType.INSTANCE;
}
// Determine the result to use.
final ExpressionResult result = !methodReturnTypes.isEmpty() ? new ExpressionResult(methodReturnTypes) : new ExpressionResult(slotType);
// Create method.
final MagikType magikType = (MagikType) exemplarType;
final EnumSet<Method.Modifier> modifiers = definition.getModifiers().stream().map(modifier -> MagikIndexer.METHOD_MODIFIER_MAPPING.get(modifier)).collect(Collectors.toCollection(() -> EnumSet.noneOf(Method.Modifier.class)));
final URI uri = magikFile.getUri();
final Location location = new Location(uri, node);
final String methodName = definition.getMethodName();
final List<Parameter> parameters = Collections.emptyList();
final Parameter assignmentParameter = null;
final Method method = magikType.addMethod(modifiers, location, methodName, parameters, assignmentParameter, result);
// TODO: Will this work?
// TODO: Ensure we don't pick up class comment of def_slotted_exemplar.
final String methodDoc = MagikCommentExtractor.extractDocComments(node).map(Token::getValue).collect(Collectors.joining("\n"));
method.setDoc(methodDoc);
final Path path = Paths.get(magikFile.getUri());
this.indexedMethods.get(path).add(method);
LOGGER.debug("Indexed method: {}", method);
}
use of nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult in project magik-tools by StevenLooman.
the class SignatureHelpProvider method provideSignatureHelp.
/**
* Provide a {{SignatureHelp}} for {{position}} in {{path}}.
* @param magikFile Magik file.
* @param position Position in file.
* @return {{SignatureHelp}}.
*/
public SignatureHelp provideSignatureHelp(final MagikTypedFile magikFile, final Position position) {
// Get intended method and called type.
final AstNode node = magikFile.getTopNode();
AstNode currentNode = AstQuery.nodeAt(node, Lsp4jConversion.positionFromLsp4j(position));
if (currentNode != null && currentNode.isNot(MagikGrammar.METHOD_INVOCATION)) {
currentNode = currentNode.getFirstAncestor(MagikGrammar.METHOD_INVOCATION);
}
if (currentNode == null) {
return new SignatureHelp(Collections.emptyList(), null, null);
}
final MethodInvocationNodeHelper helper = new MethodInvocationNodeHelper(currentNode);
final String methodName = helper.getMethodName();
if (methodName == null) {
return new SignatureHelp(Collections.emptyList(), null, null);
}
final LocalTypeReasoner reasoner = magikFile.getTypeReasoner();
final AstNode previousSiblingNode = currentNode.getPreviousSibling();
final ExpressionResult result = reasoner.getNodeType(previousSiblingNode);
final ITypeKeeper typeKeeper = magikFile.getTypeKeeper();
final AbstractType unsetType = typeKeeper.getType(GlobalReference.of("sw:unset"));
AbstractType type = result.get(0, unsetType);
LOGGER.debug("Provide signature for type: {}, method: {}", type.getFullName(), methodName);
final List<SignatureInformation> sigInfos;
if (type == UndefinedType.INSTANCE) {
// Provide all methods with the name.
sigInfos = typeKeeper.getTypes().stream().flatMap(signatureType -> signatureType.getMethods().stream()).filter(method -> method.getName().startsWith(methodName)).map(method -> new SignatureInformation(method.getSignature(), method.getDoc(), null)).collect(Collectors.toList());
} else {
if (type == SelfType.INSTANCE) {
final AstNode methodDefNode = currentNode.getFirstAncestor(MagikGrammar.METHOD_DEFINITION);
final MethodDefinitionNodeHelper methodDefHelper = new MethodDefinitionNodeHelper(methodDefNode);
final GlobalReference globalRef = methodDefHelper.getTypeGlobalReference();
type = typeKeeper.getType(globalRef);
}
// Provide methods for this type with the name.
sigInfos = type.getMethods().stream().filter(method -> method.getName().startsWith(methodName)).map(method -> new SignatureInformation(method.getSignature(), method.getDoc(), null)).collect(Collectors.toList());
}
return new SignatureHelp(sigInfos, null, null);
}
Aggregations