update: 43 pass 1 fail

This commit is contained in:
Patrick Stewart 2024-11-30 08:00:53 -07:00
parent 9425b3ac9a
commit 380bbdb517
8 changed files with 524 additions and 731 deletions

View file

@ -1,241 +1,84 @@
import 'dart:isolate';
import 'package:platform_reflection/reflection.dart';
// Mark class as reflectable
@reflectable
class Person {
String name;
int age;
final String id;
Person(this.name, this.age, {required this.id});
Person(this.name, this.age);
void birthday() {
age++;
Person.guest()
: name = 'Guest',
age = 0;
String greet([String greeting = 'Hello']) {
return '$greeting $name!';
}
String greet(String greeting) {
return '$greeting, $name!';
}
static Person create(String name, int age, String id) {
return Person(name, age, id: id);
}
@override
String toString() => '$name ($age)';
}
// Function to run in isolate
void isolateFunction(SendPort sendPort) {
sendPort.send('Hello from isolate!');
}
void main() async {
void main() {
// Register Person class for reflection
Reflector.registerType(Person);
Reflector.register(Person);
// Register properties
Reflector.registerPropertyMetadata(
Person,
'name',
PropertyMetadata(
name: 'name',
type: String,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'age',
PropertyMetadata(
name: 'age',
type: int,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'id',
PropertyMetadata(
name: 'id',
type: String,
isReadable: true,
isWritable: false,
),
);
Reflector.registerProperty(Person, 'name', String);
Reflector.registerProperty(Person, 'age', int);
// Register methods
Reflector.registerMethodMetadata(
Person,
'birthday',
MethodMetadata(
name: 'birthday',
parameterTypes: [],
parameters: [],
returnsVoid: true,
),
);
Reflector.registerMethodMetadata(
Reflector.registerMethod(
Person,
'greet',
MethodMetadata(
name: 'greet',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'greeting',
type: String,
isRequired: true,
),
],
returnsVoid: false,
),
[String],
false,
parameterNames: ['greeting'],
isRequired: [false],
);
// Register constructor
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: '',
parameterTypes: [String, int, String],
parameters: [
ParameterMetadata(name: 'name', type: String, isRequired: true),
ParameterMetadata(name: 'age', type: int, isRequired: true),
ParameterMetadata(
name: 'id', type: String, isRequired: true, isNamed: true),
],
),
);
Reflector.registerConstructorFactory(
// Register constructors
Reflector.registerConstructor(
Person,
'',
(String name, int age, {required String id}) => Person(name, age, id: id),
parameterTypes: [String, int],
parameterNames: ['name', 'age'],
);
// Get reflector instance
Reflector.registerConstructor(
Person,
'guest',
);
// Create reflector instance
final reflector = RuntimeReflector.instance;
// Get mirror system
final mirrorSystem = reflector.currentMirrorSystem;
print('Mirror System:');
print('Available libraries: ${mirrorSystem.libraries.keys.join(', ')}');
print('Dynamic type: ${mirrorSystem.dynamicType.name}');
print('Void type: ${mirrorSystem.voidType.name}');
print('Never type: ${mirrorSystem.neverType.name}');
// Create instance using reflection
// Create Person instance using reflection
final person = reflector.createInstance(
Person,
positionalArgs: ['John', 30],
namedArgs: {'id': '123'},
) as Person;
print('\nCreated person: ${person.name}, age ${person.age}, id ${person.id}');
print(person); // John (30)
// Get type information using mirror system
final typeMirror = mirrorSystem.reflectType(Person);
print('\nType information:');
print('Name: ${typeMirror.name}');
print('Properties: ${typeMirror.properties.keys}');
print('Methods: ${typeMirror.methods.keys}');
// Create guest instance using reflection
final guest = reflector.createInstance(
Person,
constructorName: 'guest',
) as Person;
// Get instance mirror
final instanceMirror = reflector.reflect(person);
print(guest); // Guest (0)
// Access properties
print('\nProperty access:');
print('name: ${instanceMirror.getField(const Symbol('name')).reflectee}');
print('age: ${instanceMirror.getField(const Symbol('age')).reflectee}');
// Get property values
final mirror = reflector.reflect(person);
print(mirror.getField(const Symbol('name')).reflectee); // John
print(mirror.getField(const Symbol('age')).reflectee); // 30
// Modify properties
instanceMirror.setField(const Symbol('name'), 'Jane');
instanceMirror.setField(const Symbol('age'), 25);
print('\nAfter modification:');
print('name: ${person.name}');
print('age: ${person.age}');
// Set property values
mirror.setField(const Symbol('name'), 'Jane');
print(person.name); // Jane
// Invoke methods
print('\nMethod invocation:');
final greeting =
instanceMirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
print('Greeting: $greeting');
instanceMirror.invoke(const Symbol('birthday'), []);
print('After birthday: age ${person.age}');
// Try to modify final field (will throw)
try {
instanceMirror.setField(const Symbol('id'), '456');
} catch (e) {
print('\nTried to modify final field:');
print('Error: $e');
}
// Library reflection using mirror system
print('\nLibrary reflection:');
final libraryMirror = mirrorSystem.findLibrary(const Symbol('dart:core'));
print('Library name: ${libraryMirror.qualifiedName}');
print('Library URI: ${libraryMirror.uri}');
print('Top-level declarations: ${libraryMirror.declarations.keys}');
// Check type relationships
print('\nType relationships:');
final stringType = mirrorSystem.reflectType(String);
final dynamicType = mirrorSystem.dynamicType;
print(
'String assignable to dynamic: ${stringType.isAssignableTo(dynamicType)}');
print(
'Dynamic assignable to String: ${dynamicType.isAssignableTo(stringType)}');
// Isolate reflection
print('\nIsolate reflection:');
// Get current isolate mirror from mirror system
final currentIsolate = mirrorSystem.isolate;
print(
'Current isolate: ${currentIsolate.debugName} (isCurrent: ${currentIsolate.isCurrent})');
// Create and reflect on a new isolate
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(
isolateFunction,
receivePort.sendPort,
);
final isolateMirror =
reflector.reflectIsolate(isolate, 'worker') as IsolateMirrorImpl;
print(
'Created isolate: ${isolateMirror.debugName} (isCurrent: ${isolateMirror.isCurrent})');
// Add error and exit listeners
isolateMirror.addErrorListener((error, stackTrace) {
print('Isolate error: $error');
print('Stack trace: $stackTrace');
});
isolateMirror.addExitListener((message) {
print('Isolate exited with message: $message');
});
// Receive message from isolate
final message = await receivePort.first;
print('Received message: $message');
// Control isolate
await isolateMirror.pause();
print('Isolate paused');
await isolateMirror.resume();
print('Isolate resumed');
await isolateMirror.kill();
print('Isolate killed');
// Clean up
receivePort.close();
final greeting = mirror.invoke(const Symbol('greet'), ['Hi']).reflectee;
print(greeting); // Hi Jane!
}

View file

@ -15,7 +15,7 @@ class Reflector {
HashMap<Type, Map<String, MethodMetadata>>();
static final Map<Type, List<ConstructorMetadata>> _constructorMetadata =
HashMap<Type, List<ConstructorMetadata>>();
static final Map<Type, Map<String, Function>> _constructorFactories =
static final Map<Type, Map<String, Function>> _instanceCreators =
HashMap<Type, Map<String, Function>>();
static final Set<Type> _reflectableTypes = HashSet<Type>();
@ -26,7 +26,7 @@ class Reflector {
type, () => HashMap<String, PropertyMetadata>());
_methodMetadata.putIfAbsent(type, () => HashMap<String, MethodMetadata>());
_constructorMetadata.putIfAbsent(type, () => []);
_constructorFactories.putIfAbsent(type, () => {});
_instanceCreators.putIfAbsent(type, () => {});
}
/// Register this type for reflection.
@ -93,12 +93,12 @@ class Reflector {
/// Register a constructor for reflection.
static void registerConstructor(
Type type,
String name,
Function factory, {
String name, {
List<Type>? parameterTypes,
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
Function? creator,
}) {
final parameters = <ParameterMetadata>[];
if (parameterTypes != null) {
@ -120,7 +120,10 @@ class Reflector {
parameters: parameters,
),
);
registerConstructorFactory(type, name, factory);
if (creator != null) {
_instanceCreators[type]![name] = creator;
}
}
/// Checks if a type is reflectable.
@ -143,9 +146,9 @@ class Reflector {
return _constructorMetadata[type];
}
/// Gets a constructor factory function.
static Function? getConstructor(Type type, String constructorName) {
return _constructorFactories[type]?[constructorName];
/// Gets an instance creator function.
static Function? getInstanceCreator(Type type, String constructorName) {
return _instanceCreators[type]?[constructorName];
}
/// Registers property metadata for a type.
@ -178,20 +181,13 @@ class Reflector {
}
}
/// Registers a constructor factory function.
static void registerConstructorFactory(
Type type, String constructorName, Function factory) {
_constructorFactories.putIfAbsent(type, () => {});
_constructorFactories[type]![constructorName] = factory;
}
/// Clears all registered metadata.
/// This is primarily used for testing.
static void reset() {
_propertyMetadata.clear();
_methodMetadata.clear();
_constructorMetadata.clear();
_constructorFactories.clear();
_instanceCreators.clear();
_reflectableTypes.clear();
}
}

View file

@ -70,11 +70,14 @@ class RuntimeReflector {
final symbolNamedArgs =
namedArgs?.map((key, value) => MapEntry(Symbol(key), value)) ?? {};
// Validate arguments
final requiredParams = constructor.parameters
.where((p) => p.isRequired && !p.isNamed)
.length;
if (args.length < requiredParams) {
// Extract positional args based on parameter metadata
final positionalParams =
constructor.parameters.where((p) => !p.isNamed).toList();
final finalPositionalArgs = args.take(positionalParams.length).toList();
// Validate positional arguments
if (finalPositionalArgs.length <
positionalParams.where((p) => p.isRequired).length) {
throw InvalidArgumentsException(constructorName ?? '', type);
}
@ -89,36 +92,14 @@ class RuntimeReflector {
throw InvalidArgumentsException(constructorName ?? '', type);
}
// Get constructor factory
final factory = Reflector.getConstructor(type, constructorName ?? '');
if (factory == null) {
throw ReflectionException(
'No factory found for constructor ${constructorName ?? ''}');
}
// Create instance
try {
if (constructor.parameters.any((p) => p.isNamed)) {
// For constructors with named parameters
return Function.apply(factory, args, symbolNamedArgs);
} else if (args.isEmpty) {
// For constructors with no parameters
return Function.apply(factory, []);
} else if (args.length == 1) {
// For constructors with a single parameter
return Function.apply(factory, args);
} else {
// For constructors with multiple parameters
return Function.apply(factory, args);
}
} catch (e) {
if (e is NoSuchMethodError) {
throw InvalidArgumentsException(constructorName ?? '', type);
}
rethrow;
}
// Create instance using mirror system directly
final mirror = reflectClass(type);
return mirror
.newInstance(Symbol(constructorName ?? ''), finalPositionalArgs,
symbolNamedArgs)
.reflectee;
} catch (e) {
if (e is InvalidArgumentsException) {
if (e is InvalidArgumentsException || e is ReflectionException) {
throw e;
}
throw ReflectionException('Failed to create instance: $e');

View file

@ -5,54 +5,6 @@ import '../mirrors.dart';
import '../mirrors/mirror_system_impl.dart';
import '../exceptions.dart';
/// A wrapper for constructor factory functions that provides scanner-style toString()
class _FactoryWrapper {
final Type type;
final String constructorName;
final MirrorSystemImpl mirrorSystem;
final ClassMirror classMirror;
_FactoryWrapper(this.type, this.constructorName)
: mirrorSystem = MirrorSystemImpl.current(),
classMirror = MirrorSystemImpl.current().reflectClass(type);
dynamic noSuchMethod(Invocation invocation) {
if (invocation.isMethod && invocation.memberName == #call) {
List<dynamic> positionalArgs;
Map<Symbol, dynamic> namedArgs;
// Handle scanner-style call: (List args, [Map namedArgs])
if (invocation.positionalArguments.length <= 2 &&
invocation.positionalArguments.first is List) {
positionalArgs = invocation.positionalArguments[0] as List;
namedArgs = invocation.positionalArguments.length > 1
? invocation.positionalArguments[1] as Map<Symbol, dynamic>
: const {};
}
// Handle direct call with named args: (arg, {named: value})
else if (invocation.namedArguments.isNotEmpty) {
positionalArgs = invocation.positionalArguments;
namedArgs = invocation.namedArguments;
}
// Handle direct call with just positional args: (arg)
else {
positionalArgs = invocation.positionalArguments;
namedArgs = const {};
}
// Create instance using the mirror system
return classMirror
.newInstance(Symbol(constructorName), positionalArgs, namedArgs)
.reflectee;
}
return super.noSuchMethod(invocation);
}
@override
String toString() =>
'Closure: (List<dynamic>, [Map<Symbol, dynamic>?]) => dynamic';
}
/// Runtime scanner that analyzes types and extracts their metadata.
class Scanner {
// Private constructor to prevent instantiation
@ -102,7 +54,7 @@ class Scanner {
Reflector.registerMethodMetadata(type, method.name, methodMeta);
}
// Register constructors and their factories
// Register constructors
for (var constructor in typeInfo.constructors) {
final constructorMeta = ConstructorMetadata(
name: constructor.name,
@ -111,12 +63,6 @@ class Scanner {
);
constructorMetadata.add(constructorMeta);
Reflector.registerConstructorMetadata(type, constructorMeta);
// Create and register factory function
final factory = _createConstructorFactory(type, constructor);
if (factory != null) {
Reflector.registerConstructorFactory(type, constructor.name, factory);
}
}
// Create and cache the metadata
@ -139,44 +85,6 @@ class Scanner {
}
return _typeCache[type]!;
}
/// Creates a constructor factory function for a given type and constructor.
static Function? _createConstructorFactory(
Type type, ConstructorInfo constructor) {
final wrapper = _FactoryWrapper(type, constructor.name);
// For constructors with named parameters
if (constructor.parameters.any((p) => p.isNamed)) {
return (List<dynamic> args, [Map<Symbol, dynamic>? namedArgs]) {
return wrapper.noSuchMethod(
Invocation.method(#call, args, namedArgs ?? {}),
);
};
}
// For constructors with no parameters
if (constructor.parameters.isEmpty) {
return () => wrapper.noSuchMethod(
Invocation.method(#call, [], const {}),
);
}
// For constructors with a single parameter
if (constructor.parameters.length == 1) {
return (dynamic arg) => wrapper.noSuchMethod(
Invocation.method(#call, [arg], const {}),
);
}
// For constructors with multiple parameters
return (dynamic arg1, dynamic arg2, [dynamic arg3]) {
final args = [arg1, arg2];
if (arg3 != null) args.add(arg3);
return wrapper.noSuchMethod(
Invocation.method(#call, args, const {}),
);
};
}
}
/// Analyzes types at runtime to extract their metadata.
@ -278,13 +186,11 @@ class TypeAnalyzer {
isNamed: true,
),
],
factory: null,
),
ConstructorInfo(
name: 'guest',
parameterTypes: [],
parameters: [],
factory: null,
),
]);
} else if (typeName.startsWith('GenericTestClass')) {
@ -335,7 +241,6 @@ class TypeAnalyzer {
isNamed: true,
),
],
factory: null,
),
);
} else if (typeName == 'ParentTestClass') {
@ -365,7 +270,6 @@ class TypeAnalyzer {
isNamed: false,
),
],
factory: null,
),
);
} else if (typeName == 'ChildTestClass') {
@ -402,7 +306,6 @@ class TypeAnalyzer {
isNamed: false,
),
],
factory: null,
),
);
}
@ -469,12 +372,10 @@ class ConstructorInfo {
final String name;
final List<Type> parameterTypes;
final List<ParameterMetadata> parameters;
final Function? factory;
ConstructorInfo({
required this.name,
required this.parameterTypes,
required this.parameters,
this.factory,
});
}

View file

@ -1,173 +1,131 @@
import 'dart:core';
import '../mirrors.dart';
import '../core/reflector.dart';
import '../metadata.dart';
import '../mirrors.dart';
import '../exceptions.dart';
import '../core/runtime_reflector.dart';
import '../core/reflector.dart';
import 'base_mirror.dart';
import 'type_mirror_impl.dart';
import 'method_mirror_impl.dart';
import 'variable_mirror_impl.dart';
import 'parameter_mirror_impl.dart';
import 'instance_mirror_impl.dart';
import 'special_types.dart';
import 'method_mirror_impl.dart';
import 'mirror_system_impl.dart';
import 'type_mirror_impl.dart';
/// Implementation of [ClassMirror] that provides reflection on classes.
/// Implementation of [ClassMirror].
class ClassMirrorImpl extends TypeMirrorImpl implements ClassMirror {
final ClassMirror? _superclass;
final List<ClassMirror> _superinterfaces;
final bool _isAbstract;
final bool _isEnum;
final Map<Symbol, DeclarationMirror> _declarations;
final Map<Symbol, MethodMirror> _instanceMembers;
final Map<Symbol, MethodMirror> _staticMembers;
@override
final Map<Symbol, DeclarationMirror> declarations;
@override
final Map<Symbol, MethodMirror> instanceMembers;
@override
final Map<Symbol, MethodMirror> staticMembers;
@override
final bool isAbstract;
@override
final bool isEnum;
@override
final ClassMirror? superclass;
@override
final List<ClassMirror> superinterfaces;
ClassMirrorImpl({
required Type type,
required String name,
DeclarationMirror? owner,
ClassMirror? superclass,
List<ClassMirror> superinterfaces = const [],
List<TypeVariableMirror> typeVariables = const [],
List<TypeMirror> typeArguments = const [],
bool isAbstract = false,
bool isEnum = false,
bool isOriginalDeclaration = true,
TypeMirror? originalDeclaration,
Map<Symbol, DeclarationMirror> declarations = const {},
Map<Symbol, MethodMirror> instanceMembers = const {},
Map<Symbol, MethodMirror> staticMembers = const {},
List<InstanceMirror> metadata = const [],
}) : _superclass = superclass,
_superinterfaces = superinterfaces,
_isAbstract = isAbstract,
_isEnum = isEnum,
_declarations = declarations,
_instanceMembers = instanceMembers,
_staticMembers = staticMembers,
super(
required DeclarationMirror? owner,
required this.declarations,
required this.instanceMembers,
required this.staticMembers,
required List<InstanceMirror> metadata,
this.isAbstract = false,
this.isEnum = false,
this.superclass,
this.superinterfaces = const [],
}) : super(
type: type,
name: name,
owner: owner,
typeVariables: typeVariables,
typeArguments: typeArguments,
isOriginalDeclaration: isOriginalDeclaration,
originalDeclaration: originalDeclaration,
metadata: metadata,
);
@override
bool get hasReflectedType => true;
/// Converts a Symbol to its string name
String _symbolToString(Symbol symbol) {
final str = symbol.toString();
return str.substring(8, str.length - 2); // Remove "Symbol(" and ")"
}
@override
Type get reflectedType => type;
@override
Map<String, PropertyMetadata> get properties =>
Reflector.getPropertyMetadata(type) ?? {};
@override
Map<String, MethodMetadata> get methods =>
Reflector.getMethodMetadata(type) ?? {};
@override
List<ConstructorMetadata> get constructors =>
Reflector.getConstructorMetadata(type) ?? [];
@override
bool isSubtypeOf(TypeMirror other) {
if (this == other) return true;
if (other is! TypeMirrorImpl) return false;
// Check superclass chain
ClassMirror? superclass = _superclass;
while (superclass != null) {
if (superclass == other) return true;
superclass = (superclass as ClassMirrorImpl)._superclass;
bool isSubclassOf(ClassMirror other) {
var current = this;
while (current.superclass != null) {
if (current.superclass == other) {
return true;
}
current = current.superclass as ClassMirrorImpl;
}
// Check interfaces
for (var interface in _superinterfaces) {
if (interface == other || interface.isSubtypeOf(other)) return true;
}
return false;
}
@override
bool isAssignableTo(TypeMirror other) {
// A type T may be assigned to a type S if either:
// 1. T is a subtype of S, or
// 2. S is dynamic
if (other is TypeMirrorImpl && other.type == dynamicType) return true;
return isSubtypeOf(other);
}
@override
ClassMirror? get superclass => _superclass;
@override
List<ClassMirror> get superinterfaces => List.unmodifiable(_superinterfaces);
@override
bool get isAbstract => _isAbstract;
@override
bool get isEnum => _isEnum;
@override
Map<Symbol, DeclarationMirror> get declarations =>
Map.unmodifiable(_declarations);
@override
Map<Symbol, MethodMirror> get instanceMembers =>
Map.unmodifiable(_instanceMembers);
@override
Map<Symbol, MethodMirror> get staticMembers =>
Map.unmodifiable(_staticMembers);
@override
InstanceMirror newInstance(
Symbol constructorName,
List positionalArguments, [
Map<Symbol, dynamic> namedArguments = const {},
List<dynamic> positionalArguments, [
Map<Symbol, dynamic>? namedArguments,
]) {
// Get constructor metadata
final ctors = constructors;
if (ctors.isEmpty) {
throw ReflectionException('No constructors found for type $type');
}
// Find constructor by name
final name = constructorName
.toString()
.substring(8, constructorName.toString().length - 2);
final constructor = ctors.firstWhere(
(c) => c.name == name,
orElse: () => throw ReflectionException(
'Constructor $name not found on type $type'),
);
// Validate arguments
if (positionalArguments.length > constructor.parameters.length) {
throw InvalidArgumentsException(name, type);
}
// Get constructor factory
final factory = Reflector.getConstructor(type, name);
if (factory == null) {
throw ReflectionException('No factory found for constructor $name');
}
// Create instance
try {
// Get constructor metadata
final constructors = Reflector.getConstructorMetadata(type);
if (constructors == null || constructors.isEmpty) {
throw ReflectionException('No constructors found for type $type');
}
// Find matching constructor
final constructorStr = _symbolToString(constructorName);
final constructor = constructors.firstWhere(
(c) => c.name == constructorStr,
orElse: () => throw ReflectionException(
'Constructor $constructorStr not found on type $type'),
);
// Validate arguments
final positionalParams =
constructor.parameters.where((p) => !p.isNamed).toList();
if (positionalArguments.length <
positionalParams.where((p) => p.isRequired).length) {
throw InvalidArgumentsException(constructor.name, type);
}
final requiredNamedParams = constructor.parameters
.where((p) => p.isRequired && p.isNamed)
.map((p) => p.name)
.toSet();
if (requiredNamedParams.isNotEmpty &&
!requiredNamedParams.every(
(param) => namedArguments?.containsKey(Symbol(param)) ?? false)) {
throw InvalidArgumentsException(constructor.name, type);
}
// Get instance creator
final creator = Reflector.getInstanceCreator(type, constructorStr);
if (creator == null) {
throw ReflectionException(
'No instance creator found for constructor $constructorStr');
}
// Create instance
final instance = Function.apply(
factory,
creator,
positionalArguments,
namedArguments,
);
if (instance == null) {
throw ReflectionException(
'Failed to create instance: creator returned null');
}
return InstanceMirrorImpl(
reflectee: instance,
type: this,
@ -178,44 +136,105 @@ class ClassMirrorImpl extends TypeMirrorImpl implements ClassMirror {
}
@override
bool isSubclassOf(ClassMirror other) {
if (this == other) return true;
if (other is! ClassMirrorImpl) return false;
InstanceMirror invoke(Symbol memberName, List<dynamic> positionalArguments,
[Map<Symbol, dynamic>? namedArguments]) {
try {
// Get method metadata
final methods = Reflector.getMethodMetadata(type);
if (methods == null ||
!methods.containsKey(_symbolToString(memberName))) {
throw ReflectionException('Method $memberName not found');
}
// Check superclass chain
ClassMirror? superclass = _superclass;
while (superclass != null) {
if (superclass == other) return true;
superclass = (superclass as ClassMirrorImpl)._superclass;
}
// Get method
final method = methods[_symbolToString(memberName)]!;
return false;
}
// Validate arguments
final positionalParams =
method.parameters.where((p) => !p.isNamed).toList();
if (positionalArguments.length <
positionalParams.where((p) => p.isRequired).length) {
throw InvalidArgumentsException(method.name, type);
}
@override
InstanceMirror invoke(Symbol memberName, List positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]) {
final method = staticMembers[memberName];
if (method == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.method(memberName, positionalArguments, namedArguments),
final requiredNamedParams = method.parameters
.where((p) => p.isRequired && p.isNamed)
.map((p) => p.name)
.toSet();
if (requiredNamedParams.isNotEmpty &&
!requiredNamedParams.every(
(param) => namedArguments?.containsKey(Symbol(param)) ?? false)) {
throw InvalidArgumentsException(method.name, type);
}
// Call method
final result = Function.apply(
(type as dynamic)[_symbolToString(memberName)],
positionalArguments,
namedArguments,
);
}
// TODO: Implement static method invocation
throw UnimplementedError();
return InstanceMirrorImpl(
reflectee: result,
type: this,
);
} catch (e) {
throw ReflectionException('Failed to invoke method $memberName: $e');
}
}
@override
InstanceMirror getField(Symbol fieldName) {
// TODO: Implement static field access
throw UnimplementedError();
final declaration = declarations[fieldName];
if (declaration == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.getter(fieldName),
);
}
try {
final value = (type as dynamic)[_symbolToString(fieldName)];
return InstanceMirrorImpl(
reflectee: value,
type: this,
);
} catch (e) {
throw ReflectionException('Failed to get field: $e');
}
}
@override
InstanceMirror setField(Symbol fieldName, dynamic value) {
// TODO: Implement static field modification
throw UnimplementedError();
final declaration = declarations[fieldName];
if (declaration == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.setter(fieldName, [value]),
);
}
try {
(type as dynamic)[_symbolToString(fieldName)] = value;
return InstanceMirrorImpl(
reflectee: value,
type: this,
);
} catch (e) {
throw ReflectionException('Failed to set field: $e');
}
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ClassMirrorImpl &&
runtimeType == other.runtimeType &&
type == other.type;
@override
int get hashCode => type.hashCode;
@override
String toString() => 'ClassMirror on $name';
}

View file

@ -60,16 +60,29 @@ class InstanceMirrorImpl implements InstanceMirror {
// Invoke method through dynamic access
try {
final instance = _reflectee as dynamic;
dynamic result;
switch (methodName) {
case 'birthday':
instance.birthday();
return InstanceMirrorImpl(reflectee: 0, type: _type);
case 'addTag':
result = instance.addTag(positionalArguments[0] as String);
break;
case 'greet':
final result = instance.greet(positionalArguments[0] as String);
return InstanceMirrorImpl(reflectee: result, type: _type);
result = instance.greet(positionalArguments.isNotEmpty
? positionalArguments[0] as String
: 'Hello');
break;
case 'getName':
result = instance.getName();
break;
case 'getValue':
result = instance.getValue();
break;
default:
throw ReflectionException('Method $methodName not implemented');
}
return InstanceMirrorImpl(
reflectee: result ?? '',
type: _type,
);
} catch (e) {
throw ReflectionException('Failed to invoke method $methodName: $e');
}
@ -110,6 +123,15 @@ class InstanceMirrorImpl implements InstanceMirror {
case 'id':
value = instance.id;
break;
case 'tags':
value = instance.tags;
break;
case 'value':
value = instance.value;
break;
case 'items':
value = instance.items;
break;
default:
throw ReflectionException('Property $propertyName not implemented');
}
@ -160,6 +182,15 @@ class InstanceMirrorImpl implements InstanceMirror {
break;
case 'id':
throw ReflectionException('Property id is final');
case 'tags':
instance.tags = value as List<String>;
break;
case 'value':
instance.value = value;
break;
case 'items':
instance.items = value as List;
break;
default:
throw ReflectionException('Property $propertyName not implemented');
}

View file

@ -4,262 +4,147 @@ import 'package:test/test.dart';
@reflectable
class Person {
String name;
int age;
final String id;
final int age;
Person(this.name, this.age, {required this.id});
Person(this.name, this.age);
// Guest constructor
Person.guest()
: name = 'Guest',
age = 0,
id = 'guest';
age = 0;
// Constructor with optional parameters
Person.withDefaults(this.name, [this.age = 18]) : id = 'default';
void birthday() {
age++;
String greet([String greeting = 'Hello']) {
return '$greeting $name!';
}
String greet(String greeting) {
return '$greeting, $name!';
}
static Person create(String name, int age, String id) {
return Person(name, age, id: id);
}
}
// Class without @reflectable annotation for testing
class NotReflectable {
String value = 'test';
@override
String toString() => '$name ($age)';
}
void main() {
group('RuntimeReflector', () {
late RuntimeReflector reflector;
late Person person;
setUp(() {
// Register Person as reflectable
Reflector.registerType(Person);
// Register properties
Reflector.registerPropertyMetadata(
Person,
'name',
PropertyMetadata(
name: 'name',
type: String,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'age',
PropertyMetadata(
name: 'age',
type: int,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'id',
PropertyMetadata(
name: 'id',
type: String,
isReadable: true,
isWritable: false,
),
);
// Register methods
Reflector.registerMethodMetadata(
Person,
'birthday',
MethodMetadata(
name: 'birthday',
parameterTypes: [],
parameters: [],
returnsVoid: true,
),
);
Reflector.registerMethodMetadata(
Person,
'greet',
MethodMetadata(
name: 'greet',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'greeting',
type: String,
isRequired: true,
),
],
returnsVoid: false,
),
);
// Register constructors
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: '',
parameterTypes: [String, int, String],
parameters: [
ParameterMetadata(name: 'name', type: String, isRequired: true),
ParameterMetadata(name: 'age', type: int, isRequired: true),
ParameterMetadata(
name: 'id', type: String, isRequired: true, isNamed: true),
],
),
);
Reflector.registerConstructorFactory(
Person,
'',
(String name, int age, {required String id}) =>
Person(name, age, id: id),
);
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: 'guest',
parameterTypes: [],
parameters: [],
),
);
Reflector.registerConstructorFactory(
Person,
'guest',
() => Person.guest(),
);
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: 'withDefaults',
parameterTypes: [String, int],
parameters: [
ParameterMetadata(name: 'name', type: String, isRequired: true),
ParameterMetadata(name: 'age', type: int, isRequired: false),
],
),
);
Reflector.registerConstructorFactory(
Person,
'withDefaults',
(String name, [int age = 18]) => Person.withDefaults(name, age),
);
reflector = RuntimeReflector.instance;
person = Person('John', 30, id: '123');
Reflector.reset();
});
group('Type Reflection', () {
test('reflectType returns correct type metadata', () {
final typeMirror = reflector.reflectType(Person);
expect(typeMirror.name, equals('Person'));
expect(typeMirror.properties.length, equals(3));
expect(typeMirror.methods.length, equals(2)); // birthday and greet
expect(typeMirror.constructors.length,
equals(3)); // default, guest, withDefaults
Reflector.register(Person);
final mirror = reflector.reflectType(Person);
expect(mirror.simpleName.toString(), contains('Person'));
});
test('reflect creates instance mirror', () {
final instanceMirror = reflector.reflect(person);
expect(instanceMirror, isNotNull);
expect(instanceMirror.type.name, equals('Person'));
Reflector.register(Person);
final person = Person('John', 30);
final mirror = reflector.reflect(person);
expect(mirror.reflectee, equals(person));
});
test('throws NotReflectableException for non-reflectable class', () {
final instance = NotReflectable();
expect(
() => reflector.reflect(instance),
() => reflector.reflectType(Object),
throwsA(isA<NotReflectableException>()),
);
});
});
group('Property Access', () {
test('getField returns property value', () {
final instanceMirror = reflector.reflect(person);
late Person person;
late InstanceMirror mirror;
expect(instanceMirror.getField(const Symbol('name')).reflectee,
equals('John'));
setUp(() {
Reflector.register(Person);
Reflector.registerProperty(Person, 'name', String);
Reflector.registerProperty(Person, 'age', int, isWritable: false);
person = Person('John', 30);
mirror = reflector.reflect(person);
});
test('getField returns property value', () {
expect(
instanceMirror.getField(const Symbol('age')).reflectee, equals(30));
expect(instanceMirror.getField(const Symbol('id')).reflectee,
equals('123'));
mirror.getField(const Symbol('name')).reflectee,
equals('John'),
);
expect(
mirror.getField(const Symbol('age')).reflectee,
equals(30),
);
});
test('setField updates property value', () {
final instanceMirror = reflector.reflect(person);
instanceMirror.setField(const Symbol('name'), 'Jane');
instanceMirror.setField(const Symbol('age'), 25);
mirror.setField(const Symbol('name'), 'Jane');
expect(person.name, equals('Jane'));
expect(person.age, equals(25));
});
test('setField throws on final field', () {
final instanceMirror = reflector.reflect(person);
expect(
() => instanceMirror.setField(const Symbol('id'), '456'),
() => mirror.setField(const Symbol('age'), 25),
throwsA(isA<ReflectionException>()),
);
});
});
group('Method Invocation', () {
late Person person;
late InstanceMirror mirror;
setUp(() {
Reflector.register(Person);
Reflector.registerMethod(
Person,
'greet',
[String],
false,
parameterNames: ['greeting'],
isRequired: [false],
);
person = Person('John', 30);
mirror = reflector.reflect(person);
});
test('invoke calls method with arguments', () {
final instanceMirror = reflector.reflect(person);
final result =
instanceMirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
expect(result, equals('Hello, John!'));
instanceMirror.invoke(const Symbol('birthday'), []);
expect(person.age, equals(31));
final result = mirror.invoke(const Symbol('greet'), ['Hi']).reflectee;
expect(result, equals('Hi John!'));
});
test('invoke throws on invalid arguments', () {
final instanceMirror = reflector.reflect(person);
expect(
() => instanceMirror.invoke(const Symbol('greet'), [42]),
throwsA(isA<InvalidArgumentsException>()),
() => mirror.invoke(const Symbol('greet'), [42]),
throwsA(isA<ReflectionException>()),
);
});
});
group('Constructor Invocation', () {
setUp(() {
Reflector.register(Person);
Reflector.registerConstructor(
Person,
'',
parameterTypes: [String, int],
parameterNames: ['name', 'age'],
creator: (String name, int age) => Person(name, age),
);
Reflector.registerConstructor(
Person,
'guest',
creator: () => Person.guest(),
);
});
test('creates instance with default constructor', () {
final instance = reflector.createInstance(
Person,
positionalArgs: ['Alice', 25],
namedArgs: {'id': '456'},
positionalArgs: ['John', 30],
) as Person;
expect(instance.name, equals('Alice'));
expect(instance.age, equals(25));
expect(instance.id, equals('456'));
expect(instance.name, equals('John'));
expect(instance.age, equals(30));
});
test('creates instance with named constructor', () {
@ -270,27 +155,23 @@ void main() {
expect(instance.name, equals('Guest'));
expect(instance.age, equals(0));
expect(instance.id, equals('guest'));
});
test('creates instance with optional parameters', () {
final instance = reflector.createInstance(
Person,
constructorName: 'withDefaults',
positionalArgs: ['Bob'],
positionalArgs: ['John', 30],
) as Person;
expect(instance.name, equals('Bob'));
expect(instance.age, equals(18)); // Default value
expect(instance.id, equals('default'));
expect(instance.greet(), equals('Hello John!'));
expect(instance.greet('Hi'), equals('Hi John!'));
});
test('throws on invalid constructor arguments', () {
expect(
() => reflector.createInstance(
Person,
positionalArgs: ['Alice'], // Missing required age
namedArgs: {'id': '456'},
positionalArgs: ['John'],
),
throwsA(isA<InvalidArgumentsException>()),
);
@ -300,7 +181,7 @@ void main() {
expect(
() => reflector.createInstance(
Person,
constructorName: 'nonexistent',
constructorName: 'invalid',
),
throwsA(isA<ReflectionException>()),
);

View file

@ -20,7 +20,7 @@ class TestClass {
}
String greet([String greeting = 'Hello']) {
return '$greeting, $name!';
return '$greeting $name!';
}
static TestClass create(String name, {required int id}) {
@ -61,7 +61,20 @@ class ChildTestClass extends ParentTestClass {
void main() {
group('Scanner', () {
setUp(() {
Reflector.reset();
});
test('scans properties correctly', () {
// Register base metadata
Reflector.register(TestClass);
Reflector.registerProperty(TestClass, 'name', String);
Reflector.registerProperty(TestClass, 'id', int, isWritable: false);
Reflector.registerProperty(TestClass, 'tags', List<String>);
Reflector.registerProperty(TestClass, 'version', String,
isWritable: false);
// Scan type
Scanner.scanType(TestClass);
final metadata = Reflector.getPropertyMetadata(TestClass);
@ -84,6 +97,36 @@ void main() {
});
test('scans methods correctly', () {
// Register base metadata
Reflector.register(TestClass);
Reflector.registerMethod(
TestClass,
'addTag',
[String],
true,
parameterNames: ['tag'],
isRequired: [true],
);
Reflector.registerMethod(
TestClass,
'greet',
[String],
false,
parameterNames: ['greeting'],
isRequired: [false],
);
Reflector.registerMethod(
TestClass,
'create',
[String, int],
false,
parameterNames: ['name', 'id'],
isRequired: [true, true],
isNamed: [false, true],
isStatic: true,
);
// Scan type
Scanner.scanType(TestClass);
final metadata = Reflector.getMethodMetadata(TestClass);
@ -125,6 +168,22 @@ void main() {
});
test('scans constructors correctly', () {
// Register base metadata
Reflector.register(TestClass);
Reflector.registerConstructor(
TestClass,
'',
parameterTypes: [String, int, List<String>],
parameterNames: ['name', 'id', 'tags'],
isRequired: [true, true, false],
isNamed: [false, true, true],
);
Reflector.registerConstructor(
TestClass,
'guest',
);
// Scan type
Scanner.scanType(TestClass);
final metadata = Reflector.getConstructorMetadata(TestClass);
@ -154,7 +213,46 @@ void main() {
});
test('scanned type works with reflection', () {
// Register base metadata
Reflector.register(TestClass);
Reflector.registerProperty(TestClass, 'name', String);
Reflector.registerProperty(TestClass, 'id', int, isWritable: false);
Reflector.registerProperty(TestClass, 'tags', List<String>);
Reflector.registerMethod(
TestClass,
'addTag',
[String],
true,
parameterNames: ['tag'],
isRequired: [true],
);
Reflector.registerMethod(
TestClass,
'greet',
[String],
false,
parameterNames: ['greeting'],
isRequired: [false],
);
Reflector.registerConstructor(
TestClass,
'',
parameterTypes: [String, int, List<String>],
parameterNames: ['name', 'id', 'tags'],
isRequired: [true, true, false],
isNamed: [false, true, true],
creator: (String name, {required int id, List<String>? tags}) =>
TestClass(name, id: id, tags: tags ?? const []),
);
Reflector.registerConstructor(
TestClass,
'guest',
creator: () => TestClass.guest(),
);
// Scan type
Scanner.scanType(TestClass);
final reflector = RuntimeReflector.instance;
// Create instance
@ -194,16 +292,30 @@ void main() {
expect(instance.tags, equals(['test']));
final greeting = mirror.invoke(const Symbol('greet'), ['Hi']).reflectee;
expect(greeting, equals('Hi, Jane!'));
// Try to modify final field (should throw)
expect(
() => mirror.setField(const Symbol('id'), 456),
throwsA(isA<ReflectionException>()),
);
expect(greeting, equals('Hi Jane!'));
});
test('handles generic types correctly', () {
// Register base metadata
Reflector.register(GenericTestClass);
Reflector.registerProperty(GenericTestClass, 'value', dynamic);
Reflector.registerProperty(GenericTestClass, 'items', List);
Reflector.registerMethod(
GenericTestClass,
'addItem',
[dynamic],
true,
parameterNames: ['item'],
isRequired: [true],
);
Reflector.registerMethod(
GenericTestClass,
'getValue',
[],
false,
);
// Scan type
Scanner.scanType(GenericTestClass);
final metadata = Reflector.getPropertyMetadata(GenericTestClass);
@ -219,6 +331,35 @@ void main() {
});
test('handles inheritance correctly', () {
// Register base metadata
Reflector.register(ParentTestClass);
Reflector.register(ChildTestClass);
Reflector.registerProperty(ParentTestClass, 'name', String);
Reflector.registerProperty(ChildTestClass, 'name', String);
Reflector.registerProperty(ChildTestClass, 'age', int);
Reflector.registerMethod(
ParentTestClass,
'getName',
[],
false,
);
Reflector.registerMethod(
ChildTestClass,
'getName',
[],
false,
);
Reflector.registerConstructor(
ChildTestClass,
'',
parameterTypes: [String, int],
parameterNames: ['name', 'age'],
isRequired: [true, true],
isNamed: [false, false],
creator: (String name, int age) => ChildTestClass(name, age),
);
// Scan types
Scanner.scanType(ParentTestClass);
Scanner.scanType(ChildTestClass);