@@ -233,6 +233,14 @@ async def _verify_expected_with_python(
233233 "str?" ,
234234 "float?" ,
235235 "bool?" ,
236+ "property " , # Sharpy properties (auto or function-style)
237+ "property get " ,
238+ "property set " ,
239+ "property init " ,
240+ "with " , # Sharpy with statement uses IDisposable, not Python __enter__/__exit__
241+ "from System" , # .NET interop imports
242+ "from system" ,
243+ "type " , # Named tuple type aliases (type Point = tuple[x: ...])
236244 ]
237245 if any (feature in code for feature in sharpy_only_features ):
238246 return True , None , "Sharpy-specific features - skipping Python verification"
@@ -397,116 +405,172 @@ def _replace_expected_output_in_code(code: str, new_output: str) -> str:
397405 return result
398406
399407
400- # Feature focuses for code generation - matched to phases 0.1.0-0.1.18
401- # Each focus tests specific compiler functionality
402- FEATURE_FOCUSES = [
403- # Phase 0.1.3: Variables & Expressions
404- "integer_variables" , # x: int = 42
405- "float_variables" , # y: float = 3.14
406- "bool_variables" , # flag: bool = True
407- "arithmetic_operators" , # +, -, *, /, //, %, **
408- "comparison_operators" , # ==, !=, <, <=, >, >=
409- "logical_operators" , # and, or, not
410- "augmented_assignment" , # +=, -=, *=, /=
411- # Phase 0.1.4: Control Flow
412- "if_else_simple" , # basic if/else
413- "if_elif_else" , # if/elif/else chains
414- "while_loop" , # while with counter
415- "for_range_single" , # for i in range(n)
416- "for_range_start_end" , # for i in range(start, end)
417- "for_range_with_step" , # for i in range(start, end, step)
418- "break_continue" , # break/continue in loops
419- # Phase 0.1.5: Functions
420- "simple_function" , # def with parameters, return
421- "function_with_print" , # function that prints values
422- "function_calling_function" , # one function calls another
423- "function_default_params" , # def foo(x: int, y: int = 5)
424- "function_keyword_args" , # foo(x=10, y=20)
425- # Phase 0.1.6: Classes
426- "simple_class" , # class with fields
427- "class_with_init" , # class with __init__
428- "class_instance_methods" , # instance methods with self
429- "class_static_methods" , # static methods (no self)
430- "class_field_access" , # obj.field, self.field
431- # Phase 0.1.7: Inheritance & Interfaces
432- "class_inheritance" , # class Child(Parent)
433- "super_init_call" , # super().__init__()
434- "abstract_class" , # @abstract class
435- "virtual_override" , # @virtual and @override methods
436- "interface_definition" , # interface with method signatures
437- "interface_implementation" , # class implements interface
438- "access_modifiers" , # @private, @protected
439- # Phase 0.1.8: Structs & Enums
440- "struct_definition" , # struct with fields
441- "enum_definition" , # enum with values
442- "enum_usage" , # using enum values
443- # Phase 0.1.9: Type System
444- "nullable_types" , # T? syntax
445- "null_coalescing" , # ?? operator
446- "null_conditional" , # ?. operator
447- "type_narrowing" , # if x is not None
448- "type_alias" , # type UserId = int
449- "generic_class" , # class Box[T]
450- "generic_function" , # def foo[T](x: T) -> T
451- # Phase 0.1.10: Module System
452- "import_statement" , # import module
453- "from_import" , # from module import item
454- # Phase 0.1.11: F-Strings & Collections
455- "f_string_basic" , # f"Hello {name}"
456- "f_string_expressions" , # f"Result: {x + y}"
457- "list_literal" , # [1, 2, 3]
458- "dict_literal" , # {"key": value}
459- "set_literal" , # {1, 2, 3}
460- "list_comprehension" , # [x * 2 for x in range(10)]
461- "dict_comprehension" , # {k: v for k, v in items}
462- "set_comprehension" , # {x for x in items}
463- "collection_iteration" , # for item in collection
464- "collection_methods" , # .add(), .remove(), len()
465- # Phase 0.1.12: .NET Interop
466- "dotnet_import" , # from system import Console
467- "dotnet_type_usage" , # using .NET types
468- # Phase 0.1.13: Exception Handling
469- "try_except_basic" , # try/except
470- "try_except_finally" , # try/except/finally
471- "try_except_else" , # try/except/else/finally
472- "raise_exception" , # raise ValueError()
473- # Phase 0.1.14: Lambda Expressions
474- "lambda_basic" , # lambda x: x * 2
475- "lambda_multiarg" , # lambda a, b: a + b
476- "higher_order_function" , # passing lambdas
477- # Phase 0.1.15-0.1.18: Optional & Result Types
478- "optional_type" , # T?, Some(x), None()
479- "optional_unwrap" , # .unwrap(), .unwrap_or(), .map()
480- "result_type" , # T !E, Ok(x), Err(e)
481- "result_unwrap" , # .unwrap(), .unwrap_or(), .map()
482- "maybe_expression" , # maybe expr — T | None → T?
483- "try_expression" , # try expr — wraps in Result[T, E]
484- "lambda_type_inference" , # lambda params inferred from context
408+ # Feature focuses organized into tiers by coverage maturity.
409+ # Tier 1 (basics) — well-covered by existing test fixtures, sampled less often.
410+ # Tier 2 (intermediate) — moderate coverage, standard sampling.
411+ # Tier 3 (advanced/newer) — least covered, sampled most often.
412+
413+ _TIER1_BASICS : list [str ] = [
414+ # Phase 0.1.3: Variables & Expressions — extensively covered
415+ "integer_variables" ,
416+ "float_variables" ,
417+ "bool_variables" ,
418+ "arithmetic_operators" ,
419+ "comparison_operators" ,
420+ "logical_operators" ,
421+ "augmented_assignment" ,
422+ # Phase 0.1.4: Control Flow — extensively covered
423+ "if_else_simple" ,
424+ "if_elif_else" ,
425+ "while_loop" ,
426+ "for_range_single" ,
427+ "for_range_start_end" ,
428+ "for_range_with_step" ,
429+ "break_continue" ,
430+ # Phase 0.1.5: Functions — extensively covered
431+ "simple_function" ,
432+ "function_with_print" ,
433+ "function_calling_function" ,
434+ "function_default_params" ,
435+ "function_keyword_args" ,
436+ # Phase 0.1.6: Basic Classes — extensively covered
437+ "simple_class" ,
438+ "class_with_init" ,
439+ "class_instance_methods" ,
440+ "class_static_methods" ,
441+ "class_field_access" ,
442+ ]
443+
444+ _TIER2_INTERMEDIATE : list [str ] = [
445+ # Inheritance & Interfaces
446+ "class_inheritance" ,
447+ "super_init_call" ,
448+ "abstract_class" ,
449+ "virtual_override" ,
450+ "interface_definition" ,
451+ "interface_implementation" ,
452+ "access_modifiers" ,
453+ # Structs & Enums
454+ "struct_definition" ,
455+ "enum_definition" ,
456+ "enum_usage" ,
457+ # Type System
458+ "nullable_types" ,
459+ "null_coalescing" ,
460+ "null_conditional" ,
461+ "type_narrowing" ,
462+ "type_alias" ,
463+ "generic_class" ,
464+ "generic_function" ,
465+ # Module System
466+ "import_statement" ,
467+ "from_import" ,
468+ # F-Strings & Collections
469+ "f_string_basic" ,
470+ "f_string_expressions" ,
471+ "list_literal" ,
472+ "dict_literal" ,
473+ "set_literal" ,
474+ "list_comprehension" ,
475+ "dict_comprehension" ,
476+ "set_comprehension" ,
477+ "collection_iteration" ,
478+ "collection_methods" ,
479+ # .NET Interop
480+ "dotnet_import" ,
481+ "dotnet_type_usage" ,
482+ # Exception Handling
483+ "try_except_basic" ,
484+ "try_except_finally" ,
485+ "try_except_else" ,
486+ "raise_exception" ,
487+ # Lambda Expressions
488+ "lambda_basic" ,
489+ "lambda_multiarg" ,
490+ "higher_order_function" ,
491+ "lambda_type_inference" ,
485492 # Dunder Methods
486- "dunder_str" , # __str__() method
487- "dunder_eq_hash" , # __eq__() + __hash__() pair
488- "dunder_bool" , # __bool__() for truthiness
489- "dunder_len" , # __len__() + len() builtin
490- "dunder_iter" , # __iter__() + __next__() iterator protocol
491- "dunder_operators" , # __add__(), __sub__(), __mul__(), __div__(), __mod__(), plus bitwise
492- "dunder_comparison" , # __lt__(), __le__(), __gt__(), __ge__(), __ne__()
493- "dunder_unary" , # __neg__(), __pos__(), __invert__()
494- # Additional Builtins
495- "builtin_conversions" , # int(), float(), bool(), str()
496- "builtin_aggregation" , # min(), max(), sum()
497- "builtin_higher_order" , # sorted(), filter(), map(), enumerate(), zip()
498- # Containment & Tuple Types
499- "containment_test" , # x in collection, x not in collection
500- "tuple_types" , # tuple[int, str], tuple unpacking in for loops
501- # Combinations
502- "nested_if_in_loop" , # if inside for/while
503- "loop_in_function" , # for/while inside function
504- "class_with_loop" , # class with method using loop
505- "inheritance_with_override" , # override methods with logic
493+ "dunder_str" ,
494+ "dunder_eq_hash" ,
495+ "dunder_bool" ,
496+ "dunder_len" ,
497+ "dunder_iter" ,
498+ "dunder_operators" ,
499+ "dunder_comparison" ,
500+ "dunder_unary" ,
501+ # Builtins
502+ "builtin_conversions" ,
503+ "builtin_aggregation" ,
504+ "builtin_higher_order" ,
505+ "containment_test" ,
506+ "tuple_types" ,
506507]
507508
508- # Bias toward simpler tests initially - complex tests often hit unimplemented features
509- COMPLEXITY_LEVELS = ["simple" , "simple" , "simple" , "medium" , "medium" , "complex" ]
509+ _TIER3_ADVANCED : list [str ] = [
510+ # Optional & Result Types
511+ "optional_type" ,
512+ "optional_unwrap" ,
513+ "result_type" ,
514+ "result_unwrap" ,
515+ "maybe_expression" ,
516+ "try_expression" ,
517+ # Properties
518+ "auto_property" ,
519+ "function_style_property" ,
520+ "property_inheritance" ,
521+ # Tuple Unpacking & Star Patterns
522+ "tuple_unpacking_assignment" ,
523+ "tuple_unpacking_nested" ,
524+ "star_unpacking" ,
525+ # Spread Operators
526+ "spread_list" ,
527+ "spread_dict" ,
528+ "spread_set" ,
529+ "spread_call" ,
530+ # Walrus Operator
531+ "walrus_operator" ,
532+ # Pattern Matching
533+ "match_literal" ,
534+ "match_type_binding" ,
535+ "match_wildcard" ,
536+ "match_guard" ,
537+ # Context Managers
538+ "with_statement" ,
539+ # Named Tuples
540+ "named_tuple" ,
541+ # Comparison Chaining
542+ "comparison_chaining" ,
543+ # Feature Combinations (advanced)
544+ "nested_if_in_loop" ,
545+ "loop_in_function" ,
546+ "class_with_loop" ,
547+ "inheritance_with_override" ,
548+ "property_with_validation" ,
549+ "match_with_enum" ,
550+ "spread_with_comprehension" ,
551+ ]
552+
553+ # Flat list for backward compatibility (e.g. category mapping lookups).
554+ FEATURE_FOCUSES = _TIER1_BASICS + _TIER2_INTERMEDIATE + _TIER3_ADVANCED
555+
556+ # Tier weights: how likely each tier is to be sampled.
557+ # Tier 3 (advanced/newer) gets ~50%, Tier 2 ~35%, Tier 1 ~15%.
558+ _TIER_WEIGHTS : list [float ] = [0.15 , 0.35 , 0.50 ]
559+ _TIERS : list [list [str ]] = [_TIER1_BASICS , _TIER2_INTERMEDIATE , _TIER3_ADVANCED ]
560+
561+
562+ def pick_feature_focus () -> str :
563+ """Select a feature focus with weighted tier sampling.
564+
565+ Newer/less-covered features (tier 3) are chosen ~50% of the time,
566+ intermediate features ~35%, and well-covered basics ~15%.
567+ """
568+ tier = random .choices (_TIERS , weights = _TIER_WEIGHTS , k = 1 )[0 ]
569+ return random .choice (tier )
570+
571+
572+ # Bias toward medium/complex — basics are well-covered by existing fixtures.
573+ COMPLEXITY_LEVELS = ["simple" , "medium" , "medium" , "medium" , "complex" , "complex" ]
510574
511575
512576class DogfoodOrchestrator :
@@ -617,8 +681,6 @@ def _load_example_snippets(self) -> None:
617681 forbidden_patterns = [
618682 "async def" , # Not implemented
619683 "await " , # Not implemented
620- " with " , # Context managers not implemented
621- ":=" , # Walrus operator not implemented
622684 ]
623685
624686 for spy_file in snippets_dir .glob ("*.spy" ):
@@ -1744,23 +1806,6 @@ async def _quick_prevalidate(self, code: str) -> Optional[str]:
17441806 return f"Line { j + 1 } : @abstract and @virtual combined (abstract methods are inherently virtual — use only @abstract)"
17451807 break # Stop at first non-empty, non-decorator line
17461808
1747- # Regex-only checks for things the lexer doesn't cover as keyword tokens
1748- forbidden_regex_checks = [
1749- # Walrus operator (not implemented) - operator token, not keyword
1750- (r":=" , "walrus operator (not implemented)" ),
1751- # Tuple unpacking (may have issues)
1752- # Anchored to line start to avoid matching keyword arguments
1753- (r"^\w+\s*,\s*\w+\s*=[^=]" , "tuple unpacking (not fully supported)" ),
1754- ]
1755-
1756- for i , line in enumerate (lines , 1 ):
1757- stripped = line .split ("#" )[0 ].strip ()
1758- if not stripped :
1759- continue
1760- for pattern , description in forbidden_regex_checks :
1761- if re .search (pattern , stripped ):
1762- return f"Line { i } : { description } - '{ stripped [:50 ]} ...'"
1763-
17641809 return None
17651810
17661811 async def _check_forbidden_tokens_via_lexer (self , code : str ) -> Optional [str ]:
@@ -1773,10 +1818,8 @@ async def _check_forbidden_tokens_via_lexer(self, code: str) -> Optional[str]:
17731818
17741819 # Forbidden token types that indicate unimplemented features
17751820 forbidden_tokens = {
1776- "With" : "with statement (not implemented)" ,
17771821 "Async" : "async function (not implemented)" ,
17781822 "Await" : "await expression (not implemented)" ,
1779- "Match" : "pattern matching (not implemented)" ,
17801823 }
17811824
17821825 try :
@@ -1963,7 +2006,7 @@ async def run(self, iterations: Optional[int] = None) -> int:
19632006 ) # Multi-file is at least medium
19642007 else :
19652008 # Regular single-file iteration
1966- feature_focus = random . choice ( FEATURE_FOCUSES )
2009+ feature_focus = pick_feature_focus ( )
19672010 complexity = random .choice (COMPLEXITY_LEVELS )
19682011
19692012 start_time = datetime .now ()
0 commit comments