#![allow(dead_code)]
#![allow(unused_imports)]
use crate::logic::grammar::Grammar;
use crate::logic::partial::MetaParser;
use crate::validation::completability::{complete, CompletionResult};
use crate::validation::complexity::{determine_complexity_exponent, ComplexityData};
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::time::Instant;
fn fun_grammar() -> Grammar {
use std::path::Path;
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let path = Path::new(manifest_dir).join("examples").join("fun.auf");
let content = std::fs::read_to_string(&path).expect("Failed to read fun.auf");
Grammar::load(&content).expect("Failed to load fun grammar")
}
fn generate_parenthesized_literal(n: usize) -> String {
let mut out = "1".to_string();
for _ in 0..n {
out = format!("({})", out);
}
out
}
fn generate_let_literal_chain(n: usize) -> String {
if n == 0 {
return "1".to_string();
}
let mut out = String::new();
for i in 0..n {
out.push_str(&format!("let x{}: Int = 1; ", i));
}
out.push_str(&format!("x{}", n - 1));
out
}
fn generate_weird_random_fun(n: usize) -> String {
let mut rng = StdRng::seed_from_u64(0xC0FFEE_u64.wrapping_mul((n as u64) + 1));
let atoms = ["1", "0", "true", "false", "x", "y", "(1)", "(true)"];
let odd_tails = ["(", ")", "->", "-", "=>", ";", ".", ""];
let mut out = atoms[rng.gen_range(0..atoms.len())].to_string();
for i in 0..=n {
match rng.gen_range(0..6) {
0 => out = format!("({})", out),
1 => out = format!("{} {}", out, atoms[rng.gen_range(0..atoms.len())]),
2 => out = format!("let x{}: Int = 1; {}", i % 4, out),
3 => out = format!("(x: Int) => {}", out),
4 => out.push_str(&format!(
" {}",
odd_tails[rng.gen_range(0..odd_tails.len())]
)),
_ => out = format!("{} {}", atoms[rng.gen_range(0..atoms.len())], out),
}
}
out
}
fn generate_operator_chain(n: usize) -> String {
if n == 0 {
return "1".to_string();
}
let mut rng = StdRng::seed_from_u64(0xF00D_u64.wrapping_mul((n as u64) + 1));
let ops = ["+", "-", "*", "/"];
let mut out = "1".to_string();
for i in 1..=n {
let op = ops[rng.gen_range(0..ops.len())];
out = format!("{} {} {}", out, op, (i % 10).to_string());
}
out
}
fn generate_nested_lambda(n: usize) -> String {
let mut lam = String::new();
for i in 0..n {
lam.push_str(&format!("(x{}: Int) => ", i));
}
lam.push_str("1");
for i in 0..(n / 2) {
lam.push_str(&format!(" a{}", i));
}
lam
}
fn generate_complex_random_fun(n: usize) -> String {
let mut rng = StdRng::seed_from_u64(0xDEADBEEF_u64.wrapping_mul((n as u64) + 1));
let mut out = match rng.gen_range(0..3) {
0 => generate_operator_chain(n / 2),
1 => generate_nested_lambda(n / 2),
_ => generate_weird_random_fun(n / 2),
};
for i in 0..n {
match rng.gen_range(0..7) {
0 => out = format!("({})", out),
1 => out = format!("let x{}: Int = {}; {}", i, (i % 5) + 1, out),
2 => out = format!("{} + {}", out, (i % 10)),
3 => out = format!("(x: Int) => {}", out),
4 => out.push_str(&format!("; x{}", i % 6)),
5 => out = format!("if {} then {} else {}", (i % 2 == 0), out, "1"),
_ => out.push_str(" ;"),
}
}
out
}
fn generate_incomplete_let_chain(n: usize) -> String {
let mut out = String::new();
for i in 0..n {
out.push_str(&format!("let x{}: Int = 1; ", i));
}
out.push_str(&format!("let x{}: Int =", n));
out
}
fn measure_completion_time(
grammar: &Grammar,
input: &str,
max_depth: usize,
) -> std::time::Duration {
let start = Instant::now();
let _ = complete(grammar, input, max_depth, None);
start.elapsed()
}
fn run_completion_complexity_test(
grammar: &Grammar,
generator: fn(usize) -> String,
name: &str,
max_n: usize,
tries: usize,
) -> Vec<ComplexityData> {
println!("\n=== {} Complexity Test ===", name);
println!("Testing completion input sizes from 1 to {}", max_n);
assert!(tries >= max_n * 2);
let indices: Vec<usize> = (0..=tries).map(|i| ((i + max_n / 2) % max_n) + 1).collect();
let mut results = Vec::with_capacity(indices.len());
for n in indices {
let input = generator(n);
let depth_budget = n + 4;
let duration = measure_completion_time(grammar, &input, depth_budget);
results.push(ComplexityData::new(n, duration, input));
}
for r in &results {
println!("n={:2}: len={} -> {:?}", r.n, r.input.len(), r.time);
}
results
}
fn measure_parse_time(grammar: &Grammar, input: &str) -> std::time::Duration {
let mut parser = MetaParser::new(grammar.clone());
let start = Instant::now();
let _ = parser.partial(input);
start.elapsed()
}
fn run_complexity_test(
grammar: &Grammar,
generator: fn(usize) -> String,
name: &str,
max_n: usize,
tries: usize,
jobs: Option<usize>,
) -> Vec<ComplexityData> {
println!("\n=== {} Complexity Test ===", name);
println!("Testing input sizes from 1 to {}", max_n);
assert!(tries >= max_n * 2);
let results = super::run_complexity_experiment(grammar, generator, name, max_n, tries, jobs);
for r in &results {
println!("n={:2}: len={} -> {:?}", r.n, r.input.len(), r.time);
}
results
}
pub fn experiments(jobs: Option<usize>) -> Vec<(String, Vec<ComplexityData>)> {
let grammar = fun_grammar();
vec![
(
"Fun Parenthesized Literal".to_string(),
run_complexity_test(
&grammar,
generate_parenthesized_literal,
"Fun Parenthesized Literal",
4,
8,
jobs,
),
),
(
"Fun Let Literal Chain".to_string(),
run_complexity_test(
&grammar,
generate_let_literal_chain,
"Fun Let Literal Chain",
4,
8,
jobs,
),
),
(
"Fun Weird Random".to_string(),
run_complexity_test(
&grammar,
generate_weird_random_fun,
"Fun Weird Random",
8,
16,
jobs,
),
),
(
"Fun Complex Random".to_string(),
run_complexity_test(
&grammar,
generate_complex_random_fun,
"Fun Complex Random",
12,
32,
jobs,
),
),
(
"Fun Completion Let Prefix".to_string(),
run_completion_complexity_test(
&grammar,
generate_incomplete_let_chain,
"Fun Completion Let Prefix",
6,
18,
),
),
]
}
#[test]
fn fun_parenthesized_literal_complexity() {
let grammar = fun_grammar();
let data = run_complexity_test(
&grammar,
generate_parenthesized_literal,
"Fun Parenthesized Literal",
4,
8,
None,
);
let k = determine_complexity_exponent(&data);
println!("\nEmpirical complexity: O(n^{:.2})", k);
println!("Expected: near-polynomial with parser memoization");
assert!(
k < 5.0,
"Fun parenthesized-literal parsing should remain below ~O(n^5), got O(n^{:.2})",
k
);
assert!(
k > 0.01,
"Complexity exponent should be > 0 for non-trivial inputs"
);
}
#[test]
fn fun_let_literal_chain_complexity() {
let grammar = fun_grammar();
let data = run_complexity_test(
&grammar,
generate_let_literal_chain,
"Fun Let Literal Chain",
4,
8,
None,
);
let k = determine_complexity_exponent(&data);
println!("\nEmpirical complexity: O(n^{:.2})", k);
println!("Linear let-chains stress sequential grammar growth and bindings.");
assert!(
k < 5.0,
"Fun let-literal-chain parsing should stay below ~O(n^5), got O(n^{:.2})",
k
);
}
#[test]
fn fun_weird_random_complexity() {
let grammar = fun_grammar();
let data = run_complexity_test(
&grammar,
generate_weird_random_fun,
"Fun Weird Random",
8,
16,
None,
);
let k = determine_complexity_exponent(&data);
println!("\nEmpirical complexity: O(n^{:.2})", k);
println!("Weird/random prefixes simulate noisy, partially malformed edits.");
assert!(
k < 6.0,
"Fun weird-random parsing should stay below ~O(n^6), got O(n^{:.2})",
k
);
}
#[test]
fn fun_complex_random_complexity() {
let grammar = fun_grammar();
let data = run_complexity_test(
&grammar,
generate_complex_random_fun,
"Fun Complex Random",
12,
32,
None,
);
let k = determine_complexity_exponent(&data);
println!("\nEmpirical complexity: O(n^{:.2})", k);
println!("Complex-random generator mixes operator chains, nested lambdas and lets.");
assert!(
k < 8.0,
"Fun complex-random parsing should stay below ~O(n^8), got O(n^{:.2})",
k
);
}
#[test]
fn fun_completion_let_prefix_complexity() {
let grammar = fun_grammar();
let data = run_completion_complexity_test(
&grammar,
generate_incomplete_let_chain,
"Fun Completion Let Prefix",
6,
18,
);
let k = determine_complexity_exponent(&data);
println!("\nEmpirical completion complexity: O(n^{:.2})", k);
println!("Completion input grows as incomplete let-chain prefixes.");
assert!(
k < 8.0,
"Fun completion on let prefixes should stay below ~O(n^8), got O(n^{:.2})",
k
);
assert!(k > 0.01, "Complexity exponent should be > 0");
let mut observed_success = false;
for point in &data {
let input = generate_incomplete_let_chain(point.n);
let depth_budget = point.n + 4;
if matches!(
complete(&grammar, &input, depth_budget, None),
CompletionResult::Success { .. }
) {
observed_success = true;
break;
}
}
assert!(
observed_success,
"Expected at least one successful completion across sampled n"
);
}