use axon_frontend::ast::{Declaration, Program};
use axon_frontend::lexer::Lexer;
use axon_frontend::parser::Parser;
fn parse(src: &str) -> Program {
let tokens = Lexer::new(src, "t.axon").tokenize().expect("lex");
Parser::new(tokens).parse().expect("parse")
}
fn tool<'a>(p: &'a Program, name: &str) -> &'a axon_frontend::ast::ToolDefinition {
p.declarations
.iter()
.find_map(|d| match d {
Declaration::Tool(t) if t.name == name => Some(t),
_ => None,
})
.unwrap_or_else(|| panic!("tool {name} not declared"))
}
#[test]
fn tool_declares_typed_input_schema_and_output_type() {
let program = parse(
r#"
tool WebSearch {
provider: http
runtime: tool_server
parameters: {
query: String,
max_results: Int,
safesearch: Bool
}
output_type: SearchResults
}
"#,
);
let t = tool(&program, "WebSearch");
assert_eq!(t.parameters.len(), 3, "three declared input parameters");
assert_eq!(t.parameters[0].name, "query");
assert_eq!(t.parameters[0].type_expr.name, "String");
assert_eq!(t.parameters[1].name, "max_results");
assert_eq!(t.parameters[1].type_expr.name, "Int");
assert_eq!(t.parameters[2].name, "safesearch");
assert_eq!(t.parameters[2].type_expr.name, "Bool");
assert_eq!(t.output_type.as_deref(), Some("SearchResults"));
assert_eq!(t.provider, "http");
assert_eq!(t.runtime, "tool_server");
}
#[test]
fn schema_supports_generic_and_optional_param_types() {
let program = parse(
r#"
tool Enrich {
provider: http
parameters: {
ids: List<String>,
hint: String?
}
}
"#,
);
let t = tool(&program, "Enrich");
assert_eq!(t.parameters[0].name, "ids");
assert_eq!(t.parameters[0].type_expr.name, "List");
assert_eq!(t.parameters[0].type_expr.generic_param, "String");
assert_eq!(t.parameters[1].name, "hint");
assert!(t.parameters[1].type_expr.optional, "`String?` is optional");
assert_eq!(t.output_type, None);
}
#[test]
fn trailing_comma_and_empty_schema_are_tolerated() {
let program = parse(
r#"
tool A {
provider: http
parameters: {
only: String,
}
}
tool B {
provider: http
parameters: {}
}
"#,
);
assert_eq!(tool(&program, "A").parameters.len(), 1, "trailing comma ok");
assert!(tool(&program, "B").parameters.is_empty(), "empty schema ok");
}
#[test]
fn schemaless_tool_still_parses_unchanged_back_compat() {
let program = parse(
r#"
tool WebSearch {
provider: http
max_results: 5
timeout: 30s
}
"#,
);
let t = tool(&program, "WebSearch");
assert!(t.parameters.is_empty(), "no schema declared → empty");
assert_eq!(t.output_type, None);
assert_eq!(t.provider, "http");
assert_eq!(t.max_results, Some(5));
}