use of nl.ramsolutions.sw.magik.analysis.typing.types.Parameter in project magik-tools by StevenLooman.
the class MethodArgumentParameterTypeCheckTest method testNoArguments.
@Test
void testNoArguments() {
final String code = "integer.m1()";
final ITypeKeeper typeKeeper = new TypeKeeper();
final MagikType integerType = (MagikType) typeKeeper.getType(GlobalReference.of("sw:integer"));
final AbstractType symbolType = typeKeeper.getType(GlobalReference.of("sw:symbol"));
final Parameter param1 = new Parameter("p1", Parameter.Modifier.NONE, symbolType);
integerType.addMethod(EnumSet.noneOf(Method.Modifier.class), null, "m1()", List.of(param1), null, ExpressionResult.UNDEFINED);
final MagikTypedCheck check = new MethodArgumentParameterTypedCheck();
final List<MagikIssue> checkResults = this.runCheck(code, typeKeeper, check);
assertThat(checkResults).isEmpty();
}
use of nl.ramsolutions.sw.magik.analysis.typing.types.Parameter in project magik-tools by StevenLooman.
the class JsonTypeKeeperReader method handleMethod.
private void handleMethod(final JSONObject instruction) {
final String typeName = instruction.getString("type_name");
final ExpressionResult parsedResult = this.typeParser.parseExpressionResultString(typeName, SW_PAKKAGE);
final AbstractType abstractType = (AbstractType) parsedResult.get(0, UndefinedType.INSTANCE);
if (abstractType == UndefinedType.INSTANCE) {
throw new InvalidParameterException("Unknown type: " + typeName);
}
final MagikType type = (MagikType) abstractType;
final JSONArray modifiersArray = (JSONArray) instruction.getJSONArray("modifiers");
final EnumSet<Method.Modifier> modifiers = StreamSupport.stream(modifiersArray.spliterator(), false).map(String.class::cast).map(String::toUpperCase).map(Method.Modifier::valueOf).collect(Collectors.toCollection(() -> EnumSet.noneOf(Method.Modifier.class)));
final Location location = instruction.get("source_file") != JSONObject.NULL ? new Location(Path.of(instruction.getString("source_file")).toUri()) : null;
final String methodName = instruction.getString("method_name");
final List<Parameter> parameters = this.parseParameters(instruction.getJSONArray("parameters"));
final Parameter assignmentParameter;
if (methodName.contains("<<")) {
int lastIdx = parameters.size() - 1;
assignmentParameter = parameters.get(lastIdx);
parameters.remove(lastIdx);
} else {
assignmentParameter = null;
}
final ExpressionResult result = this.parseExpressionResult(instruction.get("return_types"));
final ExpressionResult loopResult = this.parseExpressionResult(instruction.get("loop_types"));
final Method method = type.addMethod(modifiers, location, methodName, parameters, assignmentParameter, result, loopResult);
if (instruction.get("doc") != JSONObject.NULL) {
final String doc = instruction.getString("doc");
method.setDoc(doc);
}
}
use of nl.ramsolutions.sw.magik.analysis.typing.types.Parameter in project magik-tools by StevenLooman.
the class JsonTypeKeeperReader method handleProcedure.
private void handleProcedure(final JSONObject instruction) {
final JSONArray modifiersArray = (JSONArray) instruction.getJSONArray("modifiers");
final EnumSet<Method.Modifier> modifiers = StreamSupport.stream(modifiersArray.spliterator(), false).map(String.class::cast).map(String::toUpperCase).map(Method.Modifier::valueOf).collect(Collectors.toCollection(() -> EnumSet.noneOf(Method.Modifier.class)));
final Location location = instruction.get("source_file") != JSONObject.NULL ? new Location(Path.of(instruction.getString("source_file")).toUri()) : null;
final List<Parameter> parameters = this.parseParameters(instruction.getJSONArray("parameters"));
final ExpressionResult result = this.parseExpressionResult(instruction.get("return_types"));
final ExpressionResult loopResult = this.parseExpressionResult(instruction.get("loop_types"));
final String name = instruction.getString("name");
final GlobalReference globalRef = GlobalReference.of(name);
final String procedureName = instruction.getString("procedure_name");
final ProcedureInstance instance = new ProcedureInstance(globalRef, procedureName);
final Method method = instance.addMethod(modifiers, location, "invoke()", parameters, null, result, loopResult);
this.typeKeeper.addType(instance);
if (instruction.get("doc") != JSONObject.NULL) {
final String doc = instruction.getString("doc");
method.setDoc(doc);
}
}
use of nl.ramsolutions.sw.magik.analysis.typing.types.Parameter in project magik-tools by StevenLooman.
the class LocalTypeReasoner method walkPostProcedureDefinition.
@Override
protected void walkPostProcedureDefinition(final AstNode node) {
// Get name of procedure.
String procName = ProcedureInstance.ANONYMOUS_PROCEDURE;
final AstNode labelNode = node.getFirstChild(MagikGrammar.LABEL);
if (labelNode != null) {
final List<AstNode> labelNodeChildren = labelNode.getChildren();
procName = labelNodeChildren.get(1).getTokenValue();
}
// Parameters.
final AstNode parametersNode = node.getFirstChild(MagikGrammar.PARAMETERS);
final List<Parameter> parameters = new ArrayList<>();
final List<AstNode> parameterNodes = parametersNode.getChildren(MagikGrammar.PARAMETER);
for (final AstNode parameterNode : parameterNodes) {
final AstNode identifierNode = parameterNode.getFirstChild(MagikGrammar.IDENTIFIER);
final String identifier = identifierNode.getTokenValue();
final ParameterNodeHelper helper = new ParameterNodeHelper(parameterNode);
final Parameter.Modifier modifier;
if (helper.isOptionalParameter()) {
modifier = Parameter.Modifier.OPTIONAL;
} else if (helper.isGatherParameter()) {
modifier = Parameter.Modifier.GATHER;
} else {
modifier = Parameter.Modifier.NONE;
}
final AbstractType type = this.getNodeType(parameterNode).get(0, UndefinedType.INSTANCE);
final Parameter parameter = new Parameter(identifier, modifier, type);
parameters.add(parameter);
}
// Result.
final ExpressionResult procResult = this.getNodeType(node);
// Loopbody result.
final ExpressionResult loopbodyResult = this.getLoopbodyNodeType(node);
// Create procedure instance.
final EnumSet<Method.Modifier> modifiers = EnumSet.noneOf(Method.Modifier.class);
final URI uri = node.getToken().getURI();
final Location location = new Location(uri, node);
final GlobalReference globalRef = GlobalReference.of(ProcedureInstance.ANONYMOUS_PROCEDURE);
final ProcedureInstance procType = new ProcedureInstance(globalRef, procName);
procType.addMethod(modifiers, location, "invoke()", parameters, null, procResult, loopbodyResult);
// Store result.
final ExpressionResult result = new ExpressionResult(procType);
this.assignAtom(node, result);
}
use of nl.ramsolutions.sw.magik.analysis.typing.types.Parameter 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);
}
Aggregations