Language System API Reference
Complete API documentation for the language system components.
LanguageRegistry
Central registry for language support.
from eiplgrader.languages.registry import LanguageRegistry
Instance Methods
register
def register(
self,
name: str,
adapter_class: Type[LanguageAdapter]
) -> None
Register a language adapter.
python registry = LanguageRegistry() registry.register(“python”, PythonAdapter)
#### get_adapter
```python
def get_adapter(
self,
name: str
) -> Optional[LanguageAdapter]
Get adapter instance for a language.
python registry = LanguageRegistry() adapter = registry.get_adapter(“python”) if adapter: config = adapter.get_config()
#### get_executor
```python
def get_executor(
self,
name: str
) -> Optional[Any]
Get executor class for a language.
python ExecutorClass = LanguageRegistry.get_executor(“java”) executor = ExecutorClass()
#### list_languages
```python
def list_languages(self) -> List[str]
Get list of supported languages.
python registry = LanguageRegistry() languages = registry.list_languages()
Returns sorted list of registered language names
e.g., [‘c’, ‘cpp’, ‘go’, ‘haskell’, ‘java’, ‘javascript’, ‘python’]
#### is_supported
```python
def is_supported(
self,
name: str
) -> bool
Check if a language is supported.
python registry = LanguageRegistry() if registry.is_supported(“rust”): print(“Rust is supported!”) else: print(“Rust is not yet supported”)
#### clear
```python
def clear(self) -> None
Clear all registered adapters.
python registry = LanguageRegistry() registry.clear() # Remove all registered languages
## LanguageAdapter
Base class for language-specific code generation.
```python
from eiplgrader.languages.base import LanguageAdapter, LanguageConfig
Abstract Methods
get_config
@abstractmethod
def get_config(self) -> LanguageConfig
Return language configuration.
Returns
LanguageConfig
object:
@dataclass
class LanguageConfig:
name: str # Canonical name
display_name: str # Display name
file_extension: str # File extension (e.g., ".py")
compile_command: Optional[str] # Compilation command template
run_command: str # Execution command template
supports_types: List[str] # Supported type names
requires_types: bool # Whether explicit types required
timeout_multiplier: float # Timeout adjustment factor
Example Implementation
def get_config(self) -> LanguageConfig:
return LanguageConfig(
name="python",
display_name="Python",
file_extension=".py",
compile_command=None,
run_command="python {source}",
supports_types=["int", "float", "str", "bool", "list", "dict"],
requires_types=False,
timeout_multiplier=1.0
)
generate_prompt
@abstractmethod
def generate_prompt(
self,
student_response: str,
function_name: str,
gen_type: str,
num_to_gen: int,
**kwargs
) -> str
Generate language-specific prompt for LLM.
python def generate_prompt(self, student_response: str, function_name: str, gen_type: str, num_to_gen: int, **kwargs) -> str: if gen_type == “cgbg”: prompt = f”"”Generate {num_to_gen} Python implementations for: Function name: {function_name} Description: {student_response}
Requirements:
- Use Python 3.9+ syntax
- Include proper error handling
- Each implementation should be different
Generate exactly {num_to_gen} implementations: “”” if “example_inputs” in kwargs: prompt += self._format_examples(kwargs[“example_inputs”], kwargs[“example_outputs”])
return prompt ```
extract_code
@abstractmethod
def extract_code(
self,
llm_response: str
) -> List[str]
Extract code blocks from LLM response.
python def extract_code(self, llm_response: str) -> List[str]: import re
# Extract markdown code blocks
pattern = r'```(?:python)?\s*\n(.*?)```'
matches = re.findall(pattern, llm_response, re.DOTALL)
if not matches:
# Fallback: extract function definitions
pattern = r'def\s+\w+.*?(?=def\s+\w+|$)'
matches = re.findall(pattern, llm_response, re.DOTALL)
return [self.normalize_code(code) for code in matches] ```
normalize_code
@abstractmethod
def normalize_code(
self,
code: str
) -> str
Normalize code format (remove comments, fix indentation).
python def normalize_code(self, code: str) -> str: # Remove comments for Python lines = [] for line in code.split(‘\n’): # Remove inline comments if ‘#’ in line: line = line[:line.index(‘#’)] line = line.rstrip() if line: # Keep non-empty lines lines.append(line)
return '\n'.join(lines) ```
Helper Methods
format_examples
def format_examples(
self,
inputs: List[Any],
outputs: List[Any]
) -> str
Format input/output examples for prompt.
python examples = adapter.format_examples( inputs=[[5], [0], [3]], outputs=[120, 1, 6] )
Returns:
Examples:
- Input: 5 → Output: 120
- Input: 0 → Output: 1
- Input: 3 → Output: 6
## LanguageExecutor
Base class for language-specific code execution.
```python
from eiplgrader.languages.base import LanguageExecutor
Abstract Methods
prepare_code
@abstractmethod
def prepare_code(
self,
code: str,
test_case: dict
) -> str
Prepare code with test harness.
python def prepare_code(self, code: str, test_case: dict) -> str: import json
params = test_case["parameters"]
func_name = test_case.get("function_name", "solution")
harness = f""" import json
}
Execute test
params = {json.dumps(params)} result = {func_name}(**params) print(json.dumps(result)) “”” return harness
#### execute_test
```python
@abstractmethod
def execute_test(
self,
code: str,
test_case: dict,
timeout: int = 5
) -> dict
Execute code and return results.
python { “passed”: bool, # Test pass/fail “expected”: Any, # Expected value “actual”: Any, # Actual value (if available) “error”: Optional[str], # Error message “error_type”: Optional[str], # Error category “stdout”: Optional[str], # Captured stdout “stderr”: Optional[str], # Captured stderr “execution_time”: float # Time in seconds }
### Common Methods
#### cleanup
```python
def cleanup(self) -> None
Clean up temporary resources.
Example
def cleanup(self):
if hasattr(self, 'temp_dir') and self.temp_dir:
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
InterpretedLanguageExecutor
Base class for interpreted languages with type inference.
from eiplgrader.languages.executors.base_executors import InterpretedLanguageExecutor
Additional Methods
validate_or_infer_types
def validate_or_infer_types(
self,
test_case: dict
) -> Tuple[dict, Any]
Validate provided types or infer from values.
python
Input without types
test_case = { “parameters”: {“x”: 5, “y”: “hello”}, “expected”: “hello5” }
params, expected = executor.validate_or_infer_types(test_case)
test_case now contains:
{
“parameters”: {“x”: 5, “y”: “hello”},
“parameter_types”: {“x”: “integer”, “y”: “string”},
“expected”: “hello5”,
“expected_type”: “string”
}
#### infer_type
```python
def infer_type(
self,
value: Any
) -> str
Infer type name from Python value.
python from eiplgrader.languages.executors.base_executors import CompiledLanguageExecutor
### Abstract Methods
#### get_type_mapping
```python
@abstractmethod
def get_type_mapping(self) -> dict
Map generic types to language-specific types.
Returns
Dictionary mapping generic to specific types.
Example
def get_type_mapping(self) -> dict:
return {
"integer": "int",
"float": "double",
"string": "String",
"boolean": "boolean",
"list": "ArrayList",
"dict": "HashMap"
}
format_value
@abstractmethod
def format_value(
self,
value: Any,
type_str: str
) -> str
Format Python value as language-specific literal.
python def format_value(self, value: Any, type_str: str) -> str: if type_str == “String”: return f’“{value}”’ elif type_str == “boolean”: return “true” if value else “false” elif type_str.startswith(“int[]”): elements = “, “.join(str(v) for v in value) return f”new int[]}” else: return str(value)
### Required Methods
#### validate_types_provided
```python
def validate_types_provided(
self,
test_case: dict
) -> None
Ensure all required type information is provided.
python
This will raise ValueError
test_case = { “parameters”: {“x”: 5}, “expected”: 10 } executor.validate_types_provided(test_case)
This is valid
test_case = { “parameters”: {“x”: 5}, “parameter_types”: {“x”: “int”}, “expected”: 10, “expected_type”: “int” } executor.validate_types_provided(test_case)
## Utility Functions
### validate_language_name
```python
def validate_language_name(
name: str
) -> str
Validate and normalize language name.
python
All return “python”
validate_language_name(“python”) validate_language_name(“Python”) validate_language_name(“py”) validate_language_name(“python3”)
## Best Practices
### Language Registration
```python
# Register during module import
def register_all_languages():
"""Register all supported languages."""
languages = [
("python", PythonAdapter),
("javascript", JSAdapter),
# ... more languages
]
for name, adapter in languages:
try:
registry.register(name, adapter)
except Exception as e:
logging.error(f"Failed to register {name}: {e}")
Type Safety
def ensure_type_compatibility(test_case: dict, language: str):
"""Ensure test case types are compatible with language."""
executor_class = LanguageRegistry.get_executor(language)
if issubclass(executor_class, CompiledLanguageExecutor):
# Requires explicit types
if "parameter_types" not in test_case:
raise ValueError(
f"{language} requires explicit parameter_types"
)
else:
# Can infer types
executor = executor_class()
executor.validate_or_infer_types(test_case)
Error Handling
def safe_execute(executor: LanguageExecutor, code: str,
test_case: dict) -> dict:
"""Execute with comprehensive error handling."""
try:
return executor.execute_test(code, test_case)
except subprocess.TimeoutExpired:
return {
"passed": False,
"error": "Execution timeout",
"error_type": "timeout"
}
except MemoryError:
return {
"passed": False,
"error": "Memory limit exceeded",
"error_type": "memory"
}
except Exception as e:
return {
"passed": False,
"error": str(e),
"error_type": "system"
}
finally:
executor.cleanup()
See Also
- Adding Languages - Guide to adding language support
- Executors - Detailed executor documentation
- Architecture - Language system design