Function bodies 267 total
Span.merge method · python · L52-L59 (8 LOC)src/bsl/ast/nodes.py
def merge(self, other: "Span") -> "Span":
"""Return a span that covers both ``self`` and ``other``."""
return Span(
start=min(self.start, other.start),
end=max(self.end, other.end),
line=min(self.line, other.line),
col=self.col if self.line <= other.line else other.col,
)AgentSpec.get_behavior method · python · L491-L496 (6 LOC)src/bsl/ast/nodes.py
def get_behavior(self, name: str) -> Behavior | None:
"""Return the behavior with the given name, or ``None`` if absent."""
for behavior in self.behaviors:
if behavior.name == name:
return behavior
return NoneAgentSpec.get_invariant method · python · L498-L503 (6 LOC)src/bsl/ast/nodes.py
def get_invariant(self, name: str) -> Invariant | None:
"""Return the invariant with the given name, or ``None`` if absent."""
for invariant in self.invariants:
if invariant.name == name:
return invariant
return NoneAstSerializer.to_dict method · python · L71-L84 (14 LOC)src/bsl/ast/serializer.py
def to_dict(self, spec: AgentSpec) -> dict[str, object]:
"""Serialize an ``AgentSpec`` to a JSON-compatible dict."""
return {
"kind": "AgentSpec",
"name": spec.name,
"version": spec.version,
"model": spec.model,
"owner": spec.owner,
"behaviors": [self._behavior_to_dict(b) for b in spec.behaviors],
"invariants": [self._invariant_to_dict(i) for i in spec.invariants],
"degradations": [self._degradation_to_dict(d) for d in spec.degradations],
"compositions": [self._composition_to_dict(c) for c in spec.compositions],
"span": self._span_to_dict(spec.span),
}AstSerializer._threshold_to_dict method · python · L89-L95 (7 LOC)src/bsl/ast/serializer.py
def _threshold_to_dict(self, t: ThresholdClause) -> dict[str, object]:
return {
"operator": t.operator,
"value": t.value,
"is_percentage": t.is_percentage,
"span": self._span_to_dict(t.span),
}AstSerializer._should_to_dict method · python · L109-L114 (6 LOC)src/bsl/ast/serializer.py
def _should_to_dict(self, c: ShouldConstraint) -> dict[str, object]:
return {
"expression": self._expr_to_dict(c.expression),
"percentage": c.percentage,
"span": self._span_to_dict(c.span),
}AstSerializer._behavior_to_dict method · python · L116-L133 (18 LOC)src/bsl/ast/serializer.py
def _behavior_to_dict(self, b: Behavior) -> dict[str, object]:
return {
"kind": "Behavior",
"name": b.name,
"when_clause": self._expr_to_dict(b.when_clause) if b.when_clause else None,
"must_constraints": [self._constraint_to_dict(c) for c in b.must_constraints],
"must_not_constraints": [
self._constraint_to_dict(c) for c in b.must_not_constraints
],
"should_constraints": [self._should_to_dict(c) for c in b.should_constraints],
"may_constraints": [self._constraint_to_dict(c) for c in b.may_constraints],
"confidence": self._threshold_to_dict(b.confidence) if b.confidence else None,
"latency": self._threshold_to_dict(b.latency) if b.latency else None,
"cost": self._threshold_to_dict(b.cost) if b.cost else None,
"escalation": self._escalation_to_dict(b.escalation) if b.escalation else None,
"audit": b.audit.Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
AstSerializer._invariant_to_dict method · python · L135-L145 (11 LOC)src/bsl/ast/serializer.py
def _invariant_to_dict(self, i: Invariant) -> dict[str, object]:
return {
"kind": "Invariant",
"name": i.name,
"constraints": [self._constraint_to_dict(c) for c in i.constraints],
"prohibitions": [self._constraint_to_dict(c) for c in i.prohibitions],
"applies_to": i.applies_to.name,
"named_behaviors": list(i.named_behaviors),
"severity": i.severity.name,
"span": self._span_to_dict(i.span),
}AstSerializer._degradation_to_dict method · python · L147-L153 (7 LOC)src/bsl/ast/serializer.py
def _degradation_to_dict(self, d: Degradation) -> dict[str, object]:
return {
"kind": "Degradation",
"fallback": d.fallback,
"condition": self._expr_to_dict(d.condition),
"span": self._span_to_dict(d.span),
}AstSerializer._composition_to_dict method · python · L155-L160 (6 LOC)src/bsl/ast/serializer.py
def _composition_to_dict(self, c: Composition) -> dict[str, object]:
if isinstance(c, Receives):
return {"kind": "Receives", "source_agent": c.source_agent, "span": self._span_to_dict(c.span)}
if isinstance(c, Delegates):
return {"kind": "Delegates", "target_agent": c.target_agent, "span": self._span_to_dict(c.span)}
raise TypeError(f"Unknown composition type: {type(c)}")AstSerializer._expr_to_dict method · python · L162-L223 (62 LOC)src/bsl/ast/serializer.py
def _expr_to_dict(self, expr: Expression) -> dict[str, object]:
if isinstance(expr, Identifier):
return {"kind": "Identifier", "name": expr.name, "span": self._span_to_dict(expr.span)}
if isinstance(expr, DotAccess):
return {"kind": "DotAccess", "parts": list(expr.parts), "span": self._span_to_dict(expr.span)}
if isinstance(expr, StringLit):
return {"kind": "StringLit", "value": expr.value, "span": self._span_to_dict(expr.span)}
if isinstance(expr, NumberLit):
return {"kind": "NumberLit", "value": expr.value, "span": self._span_to_dict(expr.span)}
if isinstance(expr, BoolLit):
return {"kind": "BoolLit", "value": expr.value, "span": self._span_to_dict(expr.span)}
if isinstance(expr, BinaryOpExpr):
return {
"kind": "BinaryOpExpr",
"op": expr.op.name,
"left": self._expr_to_dict(expr.left),
"right": self.AstSerializer.from_dict method · python · L229-L245 (17 LOC)src/bsl/ast/serializer.py
def from_dict(self, data: dict[str, object]) -> AgentSpec:
"""Deserialize an ``AgentSpec`` from a plain dict."""
return AgentSpec(
name=data["name"],
version=data.get("version"),
model=data.get("model"),
owner=data.get("owner"),
behaviors=tuple(self._behavior_from_dict(b) for b in data.get("behaviors", [])),
invariants=tuple(self._invariant_from_dict(i) for i in data.get("invariants", [])),
degradations=tuple(
self._degradation_from_dict(d) for d in data.get("degradations", [])
),
compositions=tuple(
self._composition_from_dict(c) for c in data.get("compositions", [])
),
span=self._span_from_dict(data["span"]),
)AstSerializer._threshold_from_dict method · python · L250-L256 (7 LOC)src/bsl/ast/serializer.py
def _threshold_from_dict(self, d: dict[str, object]) -> ThresholdClause:
return ThresholdClause(
operator=d["operator"],
value=float(d["value"]),
is_percentage=bool(d.get("is_percentage", False)),
span=self._span_from_dict(d["span"]),
)AstSerializer._should_from_dict method · python · L270-L275 (6 LOC)src/bsl/ast/serializer.py
def _should_from_dict(self, d: dict[str, object]) -> ShouldConstraint:
return ShouldConstraint(
expression=self._expr_from_dict(d["expression"]),
percentage=d.get("percentage"),
span=self._span_from_dict(d["span"]),
)AstSerializer._behavior_from_dict method · python · L277-L295 (19 LOC)src/bsl/ast/serializer.py
def _behavior_from_dict(self, d: dict[str, object]) -> Behavior:
return Behavior(
name=d["name"],
when_clause=self._expr_from_dict(d["when_clause"]) if d.get("when_clause") else None,
must_constraints=tuple(self._constraint_from_dict(c) for c in d.get("must_constraints", [])),
must_not_constraints=tuple(
self._constraint_from_dict(c) for c in d.get("must_not_constraints", [])
),
should_constraints=tuple(
self._should_from_dict(c) for c in d.get("should_constraints", [])
),
may_constraints=tuple(self._constraint_from_dict(c) for c in d.get("may_constraints", [])),
confidence=self._threshold_from_dict(d["confidence"]) if d.get("confidence") else None,
latency=self._threshold_from_dict(d["latency"]) if d.get("latency") else None,
cost=self._threshold_from_dict(d["cost"]) if d.get("cost") else None,
escalAbout: code-quality intelligence by Repobility · https://repobility.com
AstSerializer._invariant_from_dict method · python · L297-L306 (10 LOC)src/bsl/ast/serializer.py
def _invariant_from_dict(self, d: dict[str, object]) -> Invariant:
return Invariant(
name=d["name"],
constraints=tuple(self._constraint_from_dict(c) for c in d.get("constraints", [])),
prohibitions=tuple(self._constraint_from_dict(c) for c in d.get("prohibitions", [])),
applies_to=AppliesTo[d.get("applies_to", "ALL_BEHAVIORS")],
named_behaviors=tuple(d.get("named_behaviors", [])),
severity=Severity[d.get("severity", "HIGH")],
span=self._span_from_dict(d["span"]),
)AstSerializer._degradation_from_dict method · python · L308-L313 (6 LOC)src/bsl/ast/serializer.py
def _degradation_from_dict(self, d: dict[str, object]) -> Degradation:
return Degradation(
fallback=d["fallback"],
condition=self._expr_from_dict(d["condition"]),
span=self._span_from_dict(d["span"]),
)AstSerializer._composition_from_dict method · python · L315-L321 (7 LOC)src/bsl/ast/serializer.py
def _composition_from_dict(self, d: dict[str, object]) -> Composition:
kind = d["kind"]
if kind == "Receives":
return Receives(source_agent=d["source_agent"], span=self._span_from_dict(d["span"]))
if kind == "Delegates":
return Delegates(target_agent=d["target_agent"], span=self._span_from_dict(d["span"]))
raise ValueError(f"Unknown composition kind: {kind!r}")AstSerializer._expr_from_dict method · python · L323-L379 (57 LOC)src/bsl/ast/serializer.py
def _expr_from_dict(self, d: dict[str, object]) -> Expression:
kind = d["kind"]
span = self._span_from_dict(d["span"])
if kind == "Identifier":
return Identifier(name=d["name"], span=span)
if kind == "DotAccess":
return DotAccess(parts=tuple(d["parts"]), span=span)
if kind == "StringLit":
return StringLit(value=d["value"], span=span)
if kind == "NumberLit":
return NumberLit(value=float(d["value"]), span=span)
if kind == "BoolLit":
return BoolLit(value=bool(d["value"]), span=span)
if kind == "BinaryOpExpr":
return BinaryOpExpr(
op=BinOp[d["op"]],
left=self._expr_from_dict(d["left"]),
right=self._expr_from_dict(d["right"]),
span=span,
)
if kind == "UnaryOpExpr":
return UnaryOpExpr(
op=UnaryOpKind[d["op"]],
operand=self._expr_read_source function · python · L43-L52 (10 LOC)src/bsl/cli/main.py
def _read_source(path: str) -> str:
"""Read a BSL source file, exiting on error."""
try:
return Path(path).read_text(encoding="utf-8")
except FileNotFoundError:
err_console.print(f"[red]Error:[/red] File not found: {path}")
sys.exit(1)
except OSError as exc:
err_console.print(f"[red]Error:[/red] Cannot read {path}: {exc}")
sys.exit(1)_parse_or_exit function · python · L55-L69 (15 LOC)src/bsl/cli/main.py
def _parse_or_exit(source: str, path: str) -> "AgentSpec":
"""Parse BSL source, printing errors and exiting on failure."""
from bsl.lexer import LexError
from bsl.parser import ParseErrorCollection, parse
try:
return parse(source)
except LexError as exc:
err_console.print(f"[red]Lex error[/red] in {path}: {exc}")
sys.exit(1)
except ParseErrorCollection as exc:
err_console.print(f"[red]Parse errors[/red] in {path}:")
for error in exc.errors:
err_console.print(f" {error}")
sys.exit(1)_severity_color function · python · L72-L80 (9 LOC)src/bsl/cli/main.py
def _severity_color(severity_name: str) -> str:
"""Map a DiagnosticSeverity name to a Rich color string."""
colors = {
"ERROR": "red",
"WARNING": "yellow",
"INFORMATION": "blue",
"HINT": "dim",
}
return colors.get(severity_name, "white")version_command function · python · L100-L108 (9 LOC)src/bsl/cli/main.py
def version_command() -> None:
"""Show detailed version information."""
from bsl import __version__
table = Table(show_header=False, box=None)
table.add_row("[bold]bsl-lang[/bold]", f"v{__version__}")
table.add_row("Python", f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
table.add_row("Platform", sys.platform)
console.print(table)Repobility — same analyzer, your code, free for public repos · /scan/
plugins_command function · python · L117-L122 (6 LOC)src/bsl/cli/main.py
def plugins_command() -> None:
"""List all registered plugins loaded from entry-points."""
from bsl.plugins.registry import PluginRegistry
console.print("[bold]Registered plugins:[/bold]")
console.print(" (No plugins registered. Install a plugin package to see entries here.)")validate_command function · python · L133-L175 (43 LOC)src/bsl/cli/main.py
def validate_command(file: str, strict: bool) -> None:
"""Parse and validate a BSL file.
FILE is the path to the .bsl file to validate.
"""
from bsl.validator import Validator
source = _read_source(file)
spec = _parse_or_exit(source, file)
validator = Validator(strict=strict)
diagnostics = validator.validate(spec)
if not diagnostics:
console.print(f"[green]OK[/green] {file} — no issues found")
sys.exit(0)
errors = [d for d in diagnostics if d.is_error]
warnings = [d for d in diagnostics if not d.is_error]
table = Table(title=f"Validation: {file}", show_lines=True)
table.add_column("Severity", style="bold", min_width=10)
table.add_column("Code", min_width=8)
table.add_column("Location", min_width=10)
table.add_column("Message")
for d in diagnostics:
color = _severity_color(d.severity.name)
loc = f"{d.span.line}:{d.span.col}"
table.add_row(
f"[{color}]{d.severitydiff_command function · python · L186-L214 (29 LOC)src/bsl/cli/main.py
def diff_command(old: str, new: str) -> None:
"""Compare two BSL files structurally.
OLD and NEW are paths to .bsl files to compare.
"""
from bsl.diff import diff
old_source = _read_source(old)
new_source = _read_source(new)
old_spec = _parse_or_exit(old_source, old)
new_spec = _parse_or_exit(new_source, new)
changes = diff(old_spec, new_spec)
if not changes:
console.print("[green]No structural changes between the two files.[/green]")
sys.exit(0)
console.print(f"[bold]BSL Diff:[/bold] {old} → {new}\n")
for change in changes:
line = str(change)
if line.startswith("[+]"):
console.print(f"[green]{line}[/green]")
elif line.startswith("[-]"):
console.print(f"[red]{line}[/red]")
else:
console.print(f"[yellow]{line}[/yellow]")
console.print(f"\n[bold]{len(changes)}[/bold] change(s) total")fmt_command function · python · L226-L251 (26 LOC)src/bsl/cli/main.py
def fmt_command(file: str, check: bool, in_place: bool) -> None:
"""Format a BSL file to canonical style.
FILE is the path to the .bsl file to format.
Without --check or --in-place, prints the formatted output to stdout.
"""
from bsl.formatter import format_spec
source = _read_source(file)
spec = _parse_or_exit(source, file)
formatted = format_spec(spec)
if check:
if formatted == source:
console.print(f"[green]OK[/green] {file} — already formatted")
sys.exit(0)
else:
console.print(f"[yellow]NEEDS FORMATTING[/yellow] {file}")
sys.exit(1)
elif in_place:
Path(file).write_text(formatted, encoding="utf-8")
console.print(f"[green]Formatted[/green] {file}")
else:
syntax = Syntax(formatted, "text", line_numbers=True)
console.print(syntax)lint_command function · python · L262-L300 (39 LOC)src/bsl/cli/main.py
def lint_command(file: str, no_hints: bool) -> None:
"""Run lint rules against a BSL file.
FILE is the path to the .bsl file to lint.
"""
from bsl.linter import BslLinter
source = _read_source(file)
spec = _parse_or_exit(source, file)
linter = BslLinter(include_hints=not no_hints)
diagnostics = linter.lint(spec)
if not diagnostics:
console.print(f"[green]OK[/green] {file} — no lint issues found")
sys.exit(0)
table = Table(title=f"Lint: {file}", show_lines=True)
table.add_column("Severity", style="bold", min_width=10)
table.add_column("Code", min_width=10)
table.add_column("Location", min_width=10)
table.add_column("Message")
for d in diagnostics:
color = _severity_color(d.severity.name)
loc = f"{d.span.line}:{d.span.col}"
table.add_row(
f"[{color}]{d.severity.name}[/{color}]",
d.code,
loc,
d.message + (f"\n[dim]hint: {d.suggestion}[/dschema_command function · python · L318-L336 (19 LOC)src/bsl/cli/main.py
def schema_command(file: str, output_format: str, output: str | None) -> None:
"""Export a JSON Schema from a BSL file.
FILE is the path to the .bsl file to process.
"""
from bsl.schema import SchemaExporter
source = _read_source(file)
spec = _parse_or_exit(source, file)
exporter = SchemaExporter()
schema_text = exporter.to_json(spec, indent=2)
if output:
Path(output).write_text(schema_text, encoding="utf-8")
console.print(f"[green]Schema written to[/green] {output}")
else:
syntax = Syntax(schema_text, "json", line_numbers=True)
console.print(syntax)parse_command function · python · L354-L378 (25 LOC)src/bsl/cli/main.py
def parse_command(file: str, output_format: str, output: str | None) -> None:
"""Parse a BSL file and dump the AST.
FILE is the path to the .bsl file to parse.
"""
from bsl.ast import AstSerializer
source = _read_source(file)
spec = _parse_or_exit(source, file)
serializer = AstSerializer()
if output_format == "json":
text = serializer.to_json(spec, indent=2)
lang = "json"
else:
text = serializer.to_yaml(spec)
lang = "yaml"
if output:
Path(output).write_text(text, encoding="utf-8")
console.print(f"[green]AST written to[/green] {output}")
else:
syntax = Syntax(text, lang, line_numbers=True)
console.print(syntax)translate_command function · python · L401-L446 (46 LOC)src/bsl/cli/main.py
def translate_command(text: str, provider_name: str, reverse: bool) -> None:
"""Translate natural-language text to BSL directives (or vice versa).
TEXT is the natural-language description (or BSL directive when
--reverse is given) to translate.
Examples:
\b
bsl-lang translate "must never expose user credentials"
bsl-lang translate "FORBID: expose user credentials" --reverse
bsl-lang translate "must always validate input" --provider template
"""
from bsl.translate.providers import MockLLMProvider, TemplateProvider
if provider_name == "template":
provider = TemplateProvider()
else:
# "llm" without a configured LLM: fall back to TemplateProvider
# with a visible warning so the user knows what is happening.
err_console.print(
"[yellow]Warning:[/yellow] No LLM is configured. "
"Falling back to template-based translation. "
"Set up a TranslationProvider and passSource: Repobility analyzer · https://repobility.com
compile_command function · python · L469-L515 (47 LOC)src/bsl/cli/main.py
def compile_command(file: str, target: str, output: str | None) -> None:
"""Compile a BSL file into executable test code.
FILE is the path to the .bsl file to compile.
Examples:
\b
bsl-lang compile spec.bsl --target pytest
bsl-lang compile spec.bsl --target pytest --output tests/generated/
"""
from bsl.compiler import compile as bsl_compile, available_targets
source = _read_source(file)
spec = _parse_or_exit(source, file)
if target not in available_targets():
err_console.print(
f"[red]Error:[/red] Unknown target {target!r}. "
f"Available: {', '.join(available_targets())}"
)
sys.exit(1)
try:
compiler_output = bsl_compile(spec, target=target)
except Exception as exc: # noqa: BLE001
err_console.print(f"[red]Compilation error:[/red] {exc}")
sys.exit(1)
output_dir = Path(output) if output else Path.cwd()
output_dir.mkdir(parents=True, exist_ok=TCompilerOutput.summary method · python · L41-L47 (7 LOC)src/bsl/compiler/base.py
def summary(self) -> str:
"""Return a one-line human-readable summary of this output."""
file_count = len(self.files)
return (
f"Generated {self.test_count} test case(s) "
f"across {file_count} file(s)"
)CompilerTarget.compile method · python · L78-L90 (13 LOC)src/bsl/compiler/base.py
def compile(self, spec: "AgentSpec") -> CompilerOutput:
"""Compile an ``AgentSpec`` to ``CompilerOutput``.
Parameters
----------
spec:
The parsed agent specification to compile.
Returns
-------
CompilerOutput
The generated files and metadata.
"""CompilerTarget._indent method · python · L92-L104 (13 LOC)src/bsl/compiler/base.py
def _indent(self, text: str, level: int = 1) -> str:
"""Indent *text* by ``level`` indentation units.
Each unit is ``self._indent_spaces`` spaces. Blank lines are
left empty (no trailing whitespace).
"""
prefix = " " * (self._indent_spaces * level)
lines = text.splitlines()
indented_lines = [
prefix + line if line.strip() else ""
for line in lines
]
return "\n".join(indented_lines)CodeGenerator.generate method · python · L94-L108 (15 LOC)src/bsl/compiler/code_generator.py
def generate(self, expression: Expression) -> str:
"""Translate *expression* to a Python expression string.
Parameters
----------
expression:
Any node from the ``Expression`` union defined in
``bsl.ast.nodes``.
Returns
-------
str
A syntactically valid Python expression (no trailing newline).
"""
return self._dispatch(expression)CodeGenerator.generate_assertion method · python · L110-L124 (15 LOC)src/bsl/compiler/code_generator.py
def generate_assertion(self, expression: Expression) -> str:
"""Return a complete ``assert`` statement for *expression*.
Parameters
----------
expression:
The BSL expression to assert.
Returns
-------
str
E.g. ``'assert response.tone == "warm"'``
"""
python_expr = self._dispatch(expression)
return f"assert {python_expr}"CodeGenerator.generate_negated_assertion method · python · L126-L142 (17 LOC)src/bsl/compiler/code_generator.py
def generate_negated_assertion(self, expression: Expression) -> str:
"""Return an ``assert not`` statement for *expression*.
Used for ``must_not`` / ``prohibitions`` constraints.
Parameters
----------
expression:
The BSL expression that must NOT hold.
Returns
-------
str
E.g. ``'assert not (response contains profanity)'``
"""
python_expr = self._dispatch(expression)
return f"assert not ({python_expr})"CodeGenerator._dispatch method · python · L148-L175 (28 LOC)src/bsl/compiler/code_generator.py
def _dispatch(self, node: Expression) -> str:
"""Dispatch to the correct private method for *node*'s type."""
if isinstance(node, BinaryOpExpr):
return self._binary_op(node)
if isinstance(node, UnaryOpExpr):
return self._unary_op(node)
if isinstance(node, ContainsExpr):
return self._contains(node)
if isinstance(node, InListExpr):
return self._in_list(node)
if isinstance(node, BeforeExpr):
return self._before(node)
if isinstance(node, AfterExpr):
return self._after(node)
if isinstance(node, FunctionCall):
return self._function_call(node)
if isinstance(node, DotAccess):
return self._dot_access(node)
if isinstance(node, Identifier):
return self._identifier(node)
if isinstance(node, StringLit):
return self._string_lit(node)
if isinstance(node, NumberLit):
returnMethodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
CodeGenerator._binary_op method · python · L177-L187 (11 LOC)src/bsl/compiler/code_generator.py
def _binary_op(self, node: BinaryOpExpr) -> str:
left = self._dispatch(node.left)
right = self._dispatch(node.right)
if node.op in _BINOP_TO_PYTHON:
operator = _BINOP_TO_PYTHON[node.op]
# Wrap sub-expressions in parens when they contain lower-precedence ops.
left = self._maybe_paren(node.left, left)
right = self._maybe_paren(node.right, right)
return f"{left} {operator} {right}"
# Fallback for unmapped ops (should not occur in well-formed AST).
return f"({left} {node.op.name.lower()} {right})"CodeGenerator._unary_op method · python · L189-L196 (8 LOC)src/bsl/compiler/code_generator.py
def _unary_op(self, node: UnaryOpExpr) -> str:
operand = self._dispatch(node.operand)
if node.op == UnaryOpKind.NOT:
# Wrap compound expressions in parens.
if isinstance(node.operand, BinaryOpExpr | ContainsExpr | InListExpr):
return f"not ({operand})"
return f"not {operand}"
return f"({node.op.name.lower()} {operand})"CodeGenerator._contains method · python · L198-L203 (6 LOC)src/bsl/compiler/code_generator.py
def _contains(self, node: ContainsExpr) -> str:
subject = self._dispatch(node.subject)
value = self._dispatch(node.value)
# BSL "response contains 'Hello'" → Python "Hello" in response
# (``in`` membership check).
return f"{value} in {subject}"CodeGenerator._number_lit method · python · L234-L239 (6 LOC)src/bsl/compiler/code_generator.py
def _number_lit(self, node: NumberLit) -> str:
value = node.value
# Emit integers without decimal point when the value is whole.
if value == int(value):
return str(int(value))
return str(value)CodeGenerator._maybe_paren method · python · L244-L251 (8 LOC)src/bsl/compiler/code_generator.py
def _maybe_paren(self, node: Expression, rendered: str) -> str:
"""Wrap *rendered* in parentheses if *node* is a lower-precedence binary op.
This prevents operator precedence ambiguity in generated code.
"""
if isinstance(node, BinaryOpExpr) and node.op in (BinOp.AND, BinOp.OR):
return f"({rendered})"
return renderedcompile function · python · L38-L69 (32 LOC)src/bsl/compiler/__init__.py
def compile( # noqa: A001
spec: "AgentSpec",
target: str = "pytest",
) -> CompilerOutput:
"""Compile a parsed BSL ``AgentSpec`` into executable test code.
Parameters
----------
spec:
A parsed and validated ``AgentSpec`` AST.
target:
The compilation target. Currently only ``"pytest"`` is supported.
Returns
-------
CompilerOutput
A mapping of filename → generated Python source, plus metadata
such as the total test count and any compiler warnings.
Raises
------
ValueError
If ``target`` is not a registered compiler target.
"""
if target not in _REGISTRY:
available = ", ".join(sorted(_REGISTRY))
raise ValueError(
f"Unknown compiler target {target!r}. Available targets: {available}"
)
compiler_cls = _REGISTRY[target]
compiler = compiler_cls()
return compiler.compile(spec)_has_temporal function · python · L56-L70 (15 LOC)src/bsl/compiler/pytest_target.py
def _has_temporal(expression: Expression) -> bool:
"""Return True if *expression* contains a ``before``/``after`` sub-expression."""
if isinstance(expression, (BeforeExpr, AfterExpr)):
return True
if isinstance(expression, BinaryOpExpr):
return _has_temporal(expression.left) or _has_temporal(expression.right)
if isinstance(expression, UnaryOpExpr):
return _has_temporal(expression.operand)
if isinstance(expression, ContainsExpr):
return _has_temporal(expression.subject) or _has_temporal(expression.value)
if isinstance(expression, InListExpr):
return any(_has_temporal(item) for item in expression.items)
if isinstance(expression, FunctionCall):
return any(_has_temporal(arg) for arg in expression.arguments)
return FalsePytestTarget.compile method · python · L85-L168 (84 LOC)src/bsl/compiler/pytest_target.py
def compile(self, spec: AgentSpec) -> CompilerOutput:
"""Compile *spec* to a pytest test file.
Parameters
----------
spec:
The parsed BSL agent specification.
Returns
-------
CompilerOutput
A single-file output mapping
``test_<agent_snake>_spec.py`` → generated source.
"""
gen = CodeGenerator()
generated_at = datetime.now(tz=timezone.utc)
warnings: list[str] = []
sections: list[str] = []
test_count = 0
# Detect whether we need temporal helper functions.
needs_temporal = _spec_has_temporal(spec)
# ---- File header --------------------------------------------------
header = render_file_header(
agent_name=spec.name,
bsl_version=spec.version,
generated_at=generated_at,
)
sections.append(header)
# ---- Module docstring -----------------------------------About: code-quality intelligence by Repobility · https://repobility.com
_spec_has_temporal function · python · L176-L200 (25 LOC)src/bsl/compiler/pytest_target.py
def _spec_has_temporal(spec: AgentSpec) -> bool:
"""Return True if any expression in *spec* uses before/after."""
for invariant in spec.invariants:
for constraint in invariant.constraints:
if _has_temporal(constraint.expression):
return True
for prohibition in invariant.prohibitions:
if _has_temporal(prohibition.expression):
return True
for behavior in spec.behaviors:
for constraint in (
*behavior.must_constraints,
*behavior.must_not_constraints,
*behavior.may_constraints,
):
if _has_temporal(constraint.expression):
return True
for should in behavior.should_constraints:
if _has_temporal(should.expression):
return True
if behavior.when_clause and _has_temporal(behavior.when_clause):
return True
if behavior.escalation and _has_temporal(behavior.escalation.conditio_render_imports function · python · L203-L216 (14 LOC)src/bsl/compiler/pytest_target.py
def _render_imports(needs_temporal: bool) -> str:
"""Return the import block with optional temporal helpers."""
lines = [
"from __future__ import annotations",
"",
"import re",
"from typing import Any",
"",
"import pytest",
"",
]
if needs_temporal:
lines.append(TEMPORAL_HELPERS)
return "\n".join(lines)_render_agent_context_fixture function · python · L219-L281 (63 LOC)src/bsl/compiler/pytest_target.py
def _render_agent_context_fixture(agent_name: str) -> str:
"""Return the ``_AgentContext`` class and ``agent_context`` fixture."""
return f'''\
class _AgentContext:
"""Minimal mock context for {agent_name} tests.
Attribute access on this object never raises ``AttributeError`` —
unknown attributes return ``None``. Tests set attributes directly
to configure the scenario under test.
"""
def __setattr__(self, name: str, value: Any) -> None: # noqa: ANN401
object.__setattr__(self, name, value)
def __getattr__(self, name: str) -> Any: # noqa: ANN401
return _NestedContext(name)
class _NestedContext:
"""Proxy for dotted attribute access on ``_AgentContext``."""
def __init__(self, path: str) -> None:
object.__setattr__(self, "_path", path)
def __getattr__(self, name: str) -> "_NestedContext":
path = object.__getattribute__(self, "_path")
return _NestedContext(f"{{path}}.{{name}}")
def __setattpage 1 / 6next ›