Skip to content

Commit 7435456

Browse files
committed
dogfooding: Update for 0.1.6-0.1.10
1 parent 099ee53 commit 7435456

4 files changed

Lines changed: 303 additions & 149 deletions

File tree

build_tools/sharpy_dogfood/README.md

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A comprehensive testing tool that generates random/novel Sharpy code using AI, v
66

77
The dogfooding tool helps catch compiler bugs by:
88
1. **Generating** novel Sharpy code using Claude or GitHub Copilot
9-
2. **Validating** the generated code against the language spec (phases 0.1.0-0.1.5)
9+
2. **Validating** the generated code against the language spec (phases 0.1.0-0.1.10)
1010
3. **Compiling** the code using the Sharpy compiler
1111
4. **Executing** the compiled code and capturing output
1212
5. **Verifying** that the output matches expectations (via print statements)
@@ -68,32 +68,47 @@ The tool detects several types of issues:
6868

6969
## Features Tested
7070

71-
The tool tests features from implementation phases 0.1.0 through 0.1.5:
71+
The tool tests features from implementation phases 0.1.0 through 0.1.10:
7272

7373
- **0.1.0** - Lexer: tokens, keywords, operators, indentation
7474
- **0.1.1** - Parser: AST, expressions, literals
7575
- **0.1.2** - Code Generation: entry point, primitive types
7676
- **0.1.3** - Variables: declarations, assignments, operators
7777
- **0.1.4** - Control Flow: if/elif/else, for, while
78-
- **0.1.5** - Functions: definitions, positional parameters, return
78+
- **0.1.5** - Functions: definitions, parameters (positional + default), keyword arguments
79+
- **0.1.6** - Classes: class definitions, fields, `__init__`, instance methods, static methods
80+
- **0.1.7** - Inheritance & Interfaces: single inheritance, abstract classes, interfaces, decorators (`@virtual`, `@override`, `@abstract`, `@final`)
81+
- **0.1.8** - Structs & Enums: value types (structs), enumerations
82+
- **0.1.9** - Type System: nullable types (`T?`), type aliases, basic generics, null coalescing (`??`), null conditional (`?.`)
83+
- **0.1.10** - Module System: imports, module resolution, multi-file compilation
7984

8085
### Allowed Features (Strict)
8186

8287
✅ Variables: `x: int = 42`, `x = 42` (inference)
83-
✅ Types: `int`, `str`, `bool`, `float` only
84-
✅ Operators: `+`, `-`, `*`, `/`, `//`, `%`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `and`, `or`, `not`
88+
✅ Types: `int`, `str`, `bool`, `float`, plus nullable variants `T?`
89+
✅ Operators: `+`, `-`, `*`, `/`, `//`, `%`, `**`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `and`, `or`, `not`, `??`, `?.`
8590
✅ Control flow: `if/elif/else`, `while`, `for i in range(...)`
86-
✅ Functions: `def name(param: type) -> return_type:`
91+
✅ Functions: `def name(param: type) -> return_type:`, default params, keyword args
92+
✅ Classes: `class Name:`, fields, `__init__`, instance/static methods
93+
✅ Inheritance: `class Child(Parent):`, `super().__init__()`, `@virtual`, `@override`
94+
✅ Interfaces: `interface IName:`, multiple interface implementation
95+
✅ Abstract: `@abstract` classes and methods
96+
✅ Structs: `struct Name:` (value types)
97+
✅ Enums: `enum Name:` with explicit values
98+
✅ Generics: `class Box[T]:`, `def foo[T](x: T) -> T:`
99+
✅ Type aliases: `type UserId = int`
100+
✅ Imports: `import module`, `from module import item`
87101
✅ Built-ins: `print()`, `range()`
88102

89103
### Forbidden Features (Not Yet Implemented)
90104

91105
❌ f-strings, string concatenation
92-
❌ Default parameters, keyword arguments
93-
❌ Classes, structs, interfaces
94-
❌ Lists, dicts, sets
95-
❌ Imports, exceptions, lambdas
96-
❌ Nullable types, type aliases
106+
❌ Lists, dicts, sets literals
107+
❌ List comprehensions
108+
❌ .NET interop imports (`from system import ...`)
109+
❌ Exceptions (try/except)
110+
❌ Lambdas
111+
❌ Multiple assignment, walrus operator
97112

98113
## Validation
99114

build_tools/sharpy_dogfood/config.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class Config(BaseConfig):
7979
}
8080
)
8181

82-
# Feature coverage phases (0.1.0 to 0.1.5)
82+
# Feature coverage phases (0.1.0 to 0.1.10)
8383
supported_phases: list[str] = field(
8484
default_factory=lambda: [
8585
"0.1.0", # Lexer Foundation
@@ -88,6 +88,11 @@ class Config(BaseConfig):
8888
"0.1.3", # Variables & Expressions
8989
"0.1.4", # Control Flow
9090
"0.1.5", # Functions
91+
"0.1.6", # Classes
92+
"0.1.7", # Inheritance & Interfaces
93+
"0.1.8", # Structs & Enums
94+
"0.1.9", # Type System Enhancements
95+
"0.1.10", # Module System
9196
]
9297
)
9398

@@ -103,7 +108,7 @@ def phases_file(self) -> Path:
103108
def task_list_file(self) -> Path:
104109
return (
105110
self.project_root
106-
/ "docs/implementation_planning/task_list_0.1.0_to_0.1.5.md"
111+
/ "docs/implementation_planning/task_list_0.1.0_to_0.1.10.md"
107112
)
108113

109114
@property

build_tools/sharpy_dogfood/orchestrator.py

Lines changed: 97 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ def _sharpy_to_python(sharpy_code: str) -> str:
165165
166166
For basic features (phases 0.1.0-0.1.5), Sharpy is syntactically
167167
identical to Python, so minimal transformation is needed.
168+
Note: Classes, structs, enums, interfaces (0.1.6-0.1.10) may need
169+
additional conversion or skipping for Python verification.
168170
"""
169171
lines = []
170172
for line in sharpy_code.split("\n"):
@@ -239,32 +241,69 @@ def _has_multi_arg_print(line: str) -> bool:
239241
return False
240242

241243

242-
# Feature focuses for code generation - matched to phases 0.1.0-0.1.5
244+
# Feature focuses for code generation - matched to phases 0.1.0-0.1.10
243245
# Each focus tests specific compiler functionality
244246
FEATURE_FOCUSES = [
247+
# Phase 0.1.3: Variables & Expressions
245248
"integer_variables", # x: int = 42
246249
"float_variables", # y: float = 3.14
247250
"bool_variables", # flag: bool = True
248-
"arithmetic_operators", # +, -, *, /, //, %
251+
"arithmetic_operators", # +, -, *, /, //, %, **
249252
"comparison_operators", # ==, !=, <, <=, >, >=
250253
"logical_operators", # and, or, not
251254
"augmented_assignment", # +=, -=, *=, /=
255+
# Phase 0.1.4: Control Flow
252256
"if_else_simple", # basic if/else
253257
"if_elif_else", # if/elif/else chains
254258
"while_loop", # while with counter
255259
"for_range_single", # for i in range(n)
256260
"for_range_start_end", # for i in range(start, end)
257261
"for_range_with_step", # for i in range(start, end, step)
258262
"break_continue", # break/continue in loops
263+
# Phase 0.1.5: Functions
259264
"simple_function", # def with parameters, return
260265
"function_with_print", # function that prints values
261266
"function_calling_function", # one function calls another
267+
"function_default_params", # def foo(x: int, y: int = 5)
268+
"function_keyword_args", # foo(x=10, y=20)
269+
# Phase 0.1.6: Classes
270+
"simple_class", # class with fields
271+
"class_with_init", # class with __init__
272+
"class_instance_methods", # instance methods with self
273+
"class_static_methods", # static methods (no self)
274+
"class_field_access", # obj.field, self.field
275+
# Phase 0.1.7: Inheritance & Interfaces
276+
"class_inheritance", # class Child(Parent)
277+
"super_init_call", # super().__init__()
278+
"abstract_class", # @abstract class
279+
"virtual_override", # @virtual and @override methods
280+
"interface_definition", # interface with method signatures
281+
"interface_implementation", # class implements interface
282+
"access_modifiers", # @private, @protected
283+
# Phase 0.1.8: Structs & Enums
284+
"struct_definition", # struct with fields
285+
"enum_definition", # enum with values
286+
"enum_usage", # using enum values
287+
# Phase 0.1.9: Type System
288+
"nullable_types", # T? syntax
289+
"null_coalescing", # ?? operator
290+
"null_conditional", # ?. operator
291+
"type_narrowing", # if x is not None
292+
"type_alias", # type UserId = int
293+
"generic_class", # class Box[T]
294+
"generic_function", # def foo[T](x: T) -> T
295+
# Phase 0.1.10: Module System
296+
"import_statement", # import module
297+
"from_import", # from module import item
298+
# Combinations
262299
"nested_if_in_loop", # if inside for/while
263300
"loop_in_function", # for/while inside function
301+
"class_with_loop", # class with method using loop
302+
"inheritance_with_override", # override methods with logic
264303
]
265304

266305
# Bias toward simpler tests initially - complex tests often hit unimplemented features
267-
COMPLEXITY_LEVELS = ["simple", "simple", "medium"] # 2/3 simple, 1/3 medium
306+
COMPLEXITY_LEVELS = ["simple", "simple", "simple", "medium", "medium", "complex"]
268307

269308

270309
class DogfoodOrchestrator:
@@ -314,46 +353,42 @@ async def initialize(self) -> bool:
314353
def _load_example_snippets(self) -> None:
315354
"""Load example Sharpy snippets from the snippets directory.
316355
317-
Filters to only include snippets that use features from phases 0.1.0-0.1.5.
356+
Filters to only include snippets that use features from phases 0.1.0-0.1.10.
357+
Excludes snippets with v0.1.11+ features like collections, comprehensions, etc.
318358
"""
319359
snippets_dir = self.config.snippets_dir
320360
if not snippets_dir.exists():
321361
return
322362

323-
# Features that indicate code is beyond phases 0.1.0-0.1.5
363+
# Features that indicate code is beyond phases 0.1.0-0.1.10
364+
# (collections, comprehensions, exceptions, lambdas, .NET interop)
324365
forbidden_patterns = [
325-
"class ",
326-
"struct ",
327-
"interface ",
328-
"import ",
329-
"from ",
330366
"lambda",
331367
"try:",
332368
"except:",
333369
"raise ",
334-
'f"',
335-
"f'",
336-
"= [",
337-
"= {",
338-
": list",
339-
": dict",
340-
": set",
341-
"-> list",
342-
"-> dict",
343-
"Optional[",
344-
"?", # nullable types
345-
"@", # decorators
370+
'f"', # f-strings (v0.1.11)
371+
"f'", # f-strings (v0.1.11)
372+
"= [", # list literals (v0.1.11)
373+
"= {", # dict/set literals (v0.1.11)
374+
": list[", # list type (v0.1.11)
375+
": dict[", # dict type (v0.1.11)
376+
": set[", # set type (v0.1.11)
377+
"-> list[", # list return type (v0.1.11)
378+
"-> dict[", # dict return type (v0.1.11)
379+
"Optional[", # Use T? instead
380+
"from system", # .NET interop (v0.1.12)
381+
"from System", # .NET interop (v0.1.12)
382+
" for ", # comprehensions (approximate check)
346383
]
347384

348385
for spy_file in snippets_dir.glob("*.spy"):
349386
try:
350387
content = spy_file.read_text()
351388
# Only include smaller snippets without forbidden features
352-
if len(content) < 400:
353-
content_lower = content.lower()
389+
if len(content) < 500:
354390
has_forbidden = any(
355-
pattern.lower() in content_lower
356-
for pattern in forbidden_patterns
391+
pattern in content for pattern in forbidden_patterns
357392
)
358393
if not has_forbidden:
359394
self.example_snippets.append(content)
@@ -423,7 +458,7 @@ async def run_iteration(
423458
if prevalidation_error:
424459
print(f" Pre-validation failed: {prevalidation_error}", file=sys.stderr)
425460
print(
426-
" Skipping (generated code uses features beyond phases 0.1.0-0.1.5)",
461+
" Skipping (generated code uses features beyond phases 0.1.0-0.1.10)",
427462
file=sys.stderr,
428463
)
429464
return IterationResult(
@@ -598,45 +633,45 @@ def _quick_prevalidate(self, code: str) -> Optional[str]:
598633
599634
Returns None if code passes, or an error message if it fails.
600635
This catches obvious issues before expensive AI validation.
636+
637+
Validates against phases 0.1.0-0.1.10 (excludes v0.1.11+ features).
601638
"""
602639
import re
603640

604-
# Patterns that indicate features beyond phases 0.1.0-0.1.5
641+
# Patterns that indicate features beyond phases 0.1.0-0.1.10
642+
# Note: Classes, structs, interfaces, enums, imports, decorators,
643+
# nullable types, default params, keyword args ARE allowed now
605644
forbidden_checks = [
606-
(r'f"[^"]*\{', "f-string interpolation"),
607-
(r"f'[^']*\{", "f-string interpolation"),
608-
# Note: multi-argument print is checked separately with _has_multi_arg_print()
609-
(r"def\s+\w+\s*\([^)]*=\s*[^,)]+", "default parameter value"),
610-
(
611-
r"\w+\s*=\s*\w+\s*\(",
612-
None,
613-
), # skip - this is just a function call assignment
614-
(r"\(\s*\w+\s*=\s*", "keyword argument"),
615-
(r"\bclass\s+\w+", "class definition"),
616-
(r"\bstruct\s+\w+", "struct definition"),
617-
(r"\binterface\s+\w+", "interface definition"),
618-
(r"\bimport\s+", "import statement"),
619-
(r"\bfrom\s+\w+\s+import", "from import statement"),
620-
(r"\blambda\s*[^:]*:", "lambda expression"),
621-
(r"\btry\s*:", "try block"),
622-
(r"\bexcept\s*", "except block"),
623-
(r"\braise\s+", "raise statement"),
624-
(r"\bwith\s+", "with statement"),
625-
(r"\basync\s+def", "async function"),
626-
(r"\bawait\s+", "await expression"),
627-
(r":\s*list\[", "list type annotation"),
628-
(r":\s*dict\[", "dict type annotation"),
629-
(r":\s*set\[", "set type annotation"),
630-
(r":\s*\w+\?", "nullable type annotation"),
631-
(r"->\s*\w+\?", "nullable return type"),
632-
(r":\s*Optional\[", "Optional type"),
633-
(r"\[\s*\]", "empty list literal"),
634-
(r"\{\s*\}", "empty dict/set literal"),
635-
(r"\[\s*\w+.*for\s+\w+\s+in", "list comprehension"),
636-
(r"\{[^}]*for\s+\w+\s+in", "dict/set comprehension"),
637-
(r"^\s*@\w+", "decorator"),
638-
(r"\bx\s+if\s+.+\s+else\s+", "ternary expression"),
639-
(r"\w+\s*,\s*\w+\s*=", "tuple unpacking"),
645+
# String features not yet supported
646+
(r'f"[^"]*\{', "f-string interpolation (v0.1.11)"),
647+
(r"f'[^']*\{", "f-string interpolation (v0.1.11)"),
648+
# Collections (v0.1.11)
649+
(r":\s*list\[", "list type annotation (v0.1.11)"),
650+
(r":\s*dict\[", "dict type annotation (v0.1.11)"),
651+
(r":\s*set\[", "set type annotation (v0.1.11)"),
652+
(r":\s*Optional\[", "Optional type - use T? instead"),
653+
(r"\[\s*\]", "empty list literal (v0.1.11)"),
654+
(r"\{\s*\}", "empty dict/set literal (v0.1.11)"),
655+
(r"\[\s*\w+.*for\s+\w+\s+in", "list comprehension (v0.1.11)"),
656+
(r"\{[^}]*for\s+\w+\s+in", "dict/set comprehension (v0.1.11)"),
657+
# Exception handling (v0.1.13)
658+
(r"\btry\s*:", "try block (v0.1.13)"),
659+
(r"\bexcept\s*", "except block (v0.1.13)"),
660+
(r"\braise\s+", "raise statement (v0.1.13)"),
661+
# Lambdas (v0.1.14)
662+
(r"\blambda\s*[^:]*:", "lambda expression (v0.1.14)"),
663+
# Async/await (deferred)
664+
(r"\basync\s+def", "async function (deferred)"),
665+
(r"\bawait\s+", "await expression (deferred)"),
666+
# Context managers (deferred)
667+
(r"\bwith\s+", "with statement (deferred)"),
668+
# Tuple unpacking
669+
(r"\w+\s*,\s*\w+\s*=", "tuple unpacking (not supported)"),
670+
# Ternary expression
671+
(r"\bx\s+if\s+.+\s+else\s+", "ternary expression (not supported)"),
672+
# .NET interop imports (v0.1.12)
673+
(r"\bfrom\s+system\s+import", ".NET interop import (v0.1.12)"),
674+
(r"\bfrom\s+System\s+import", ".NET interop import (v0.1.12)"),
640675
]
641676

642677
lines = code.split("\n")
@@ -654,14 +689,6 @@ def _quick_prevalidate(self, code: str) -> Optional[str]:
654689
if description is None:
655690
continue
656691
if re.search(pattern, stripped):
657-
# Special case: skip "keyword argument" false positives for comparisons
658-
if description == "keyword argument":
659-
# Check if it's actually a comparison or assignment in a function call
660-
if re.search(r"\w+\s*==\s*", stripped):
661-
continue
662-
# Skip if it's a regular assignment (no parenthesis before =)
663-
if not re.search(r"\([^)]*\w+\s*=\s*[^=]", stripped):
664-
continue
665692
return f"Line {i}: {description} - '{stripped[:50]}...'"
666693

667694
return None

0 commit comments

Comments
 (0)