visitFunctionDeclaration method
void
visitFunctionDeclaration(
- FunctionDeclaration node
)
override
Implementation
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
final functionName = node.name.lexeme;
Logger.debug(
"[DeclarationVisitor.visitFunctionDeclaration] Processing function: $functionName");
if (environment.isDefinedLocally(functionName)) {
return;
}
// Handle type parameters for generic functions
Environment? tempEnvironment;
final typeParameters = node.functionExpression.typeParameters;
if (typeParameters != null) {
Logger.debug(
"[DeclarationVisitor.visitFunctionDeclaration] Function '$functionName' has ${typeParameters.typeParameters.length} type parameters");
// Create a temporary environment for type resolution
tempEnvironment = Environment(enclosing: environment);
// Create temporary type parameter placeholders
for (final typeParam in typeParameters.typeParameters) {
final paramName = typeParam.name.lexeme;
// Create a simple TypeParameter placeholder in the temp environment
final typeParamPlaceholder = TypeParameter(paramName);
tempEnvironment.define(paramName, typeParamPlaceholder);
Logger.debug(
"[DeclarationVisitor.visitFunctionDeclaration] Defined type parameter '$paramName' in temp environment");
}
}
// Use the temp environment (if any) for type resolution, otherwise use the normal environment
final resolveEnvironment = tempEnvironment ?? environment;
// Now resolve the return type (which might reference type parameters)
final returnTypeNode = node.returnType;
RuntimeType declaredReturnType;
if (returnTypeNode is NamedType) {
final typeName = returnTypeNode.name2.lexeme;
Logger.debug(
"[DeclarationVisitor.visitFunctionDeclaration] Return type node name: $typeName");
try {
final resolvedType = resolveEnvironment.get(typeName);
Logger.debug(
"[DeclarationVisitor.visitFunctionDeclaration] environment.get('$typeName') resolved to: ${resolvedType?.runtimeType} with name: ${(resolvedType is RuntimeType ? resolvedType.name : 'N/A')}");
if (resolvedType is RuntimeType) {
declaredReturnType = resolvedType;
} else {
Logger.warn(
"[DeclarationVisitor.visitFunctionDeclaration] Type '$typeName' resolved to non-RuntimeType: $resolvedType. Using placeholder.");
declaredReturnType = BridgedClass(nativeType: Object, name: typeName);
}
} on RuntimeError catch (e) {
Logger.warn(
"[DeclarationVisitor.visitFunctionDeclaration] Type '$typeName' not found in environment (RuntimeError: ${e.message}). Using placeholder.");
declaredReturnType = BridgedClass(nativeType: Object, name: typeName);
}
} else if (returnTypeNode == null) {
declaredReturnType = BridgedClass(nativeType: Object, name: 'dynamic');
} else {
// For other TypeAnnotation types, use a generic placeholder
declaredReturnType =
BridgedClass(nativeType: Object, name: 'unknown_type_placeholder');
}
bool isNullable = returnTypeNode?.question != null; // Check for 'A?'
final function = InterpretedFunction.declaration(
node,
environment, // The function captures the environment it's declared in
declaredReturnType,
isNullable);
Logger.debug(
"[DeclarationVisitor.visitFunctionDeclaration] Defining function '$functionName' with declaredReturnType: ${declaredReturnType.name} (Hash: ${declaredReturnType.hashCode})");
environment.define(functionName, function);
}