walpurgis/src/ast_builder.rs

266 lines
7.8 KiB
Rust
Raw Normal View History

use rand::Rng;
2023-11-17 15:32:12 -07:00
use rand::seq::SliceRandom;
use rand_distr::Distribution;
2023-11-17 15:32:12 -07:00
use std::collections::HashMap;
2023-11-16 16:27:03 -07:00
use crate::params::Params;
2023-11-17 15:32:12 -07:00
use crate::ast::*;
2023-11-16 16:27:03 -07:00
2023-11-18 00:15:19 -07:00
#[derive(Default)]
struct StateTracking {
int_recursion_depth: u32,
}
2023-11-16 16:27:03 -07:00
pub struct AstBuilder {
params: Params,
ast: GlobalBlock,
name_counter: u64,
2023-11-17 15:46:13 -07:00
typedef_map: HashMap<BaseType, Vec<String>>,
2023-11-17 15:32:12 -07:00
typedef_vec: Vec<(String, BaseType)>,
2023-11-18 00:15:19 -07:00
state: StateTracking,
2023-11-17 15:32:12 -07:00
// Random generation
rng: rand::rngs::ThreadRng,
2023-11-16 21:24:05 -07:00
rng_float: FloatGenerator,
2023-11-16 21:47:27 -07:00
rng_int: IntGenerator,
2023-11-16 16:27:03 -07:00
}
impl AstBuilder {
pub fn from(params: Params) -> Self {
2023-11-17 15:32:12 -07:00
let mut typedef_map = HashMap::new();
let mut typedef_vec = Vec::new();
2023-11-17 15:46:13 -07:00
typedef_map.insert(BaseType::Int, vec!["integer".to_string()]);
typedef_map.insert(BaseType::Real, vec!["real".to_string()]);
2023-11-17 15:32:12 -07:00
typedef_vec.push(("integer".to_string(), BaseType::Int));
typedef_vec.push(("real".to_string(), BaseType::Real));
2023-11-16 16:27:03 -07:00
Self {
ast: GlobalBlock::default(),
2023-11-16 21:24:05 -07:00
name_counter: 0,
2023-11-17 15:32:12 -07:00
typedef_map,
typedef_vec,
2023-11-18 00:15:19 -07:00
state: StateTracking::default(),
2023-11-16 21:24:05 -07:00
rng: rand::thread_rng(),
rng_float: FloatGenerator::new(&params),
2023-11-16 21:47:27 -07:00
rng_int: IntGenerator::new(&params),
2023-11-16 21:24:05 -07:00
params,
2023-11-16 16:27:03 -07:00
}
}
pub fn generate(&mut self) {
let mut p: f64;
2023-11-17 15:32:12 -07:00
let p1 = self.params.global_flow.end_generation;
let p2 = p1 + self.params.global_flow.gen_typedef;
loop {
p = self.rng.gen();
2023-11-17 15:32:12 -07:00
if p < p1 {
break;
2023-11-17 15:32:12 -07:00
} else if p < p2 {
let typedef = self.gen_typedef();
self.ast.push(typedef);
} else {
let decl = self.gen_decl();
self.ast.push(decl);
}
}
}
2023-11-17 14:50:06 -07:00
fn gen_decl(&mut self) -> Stat {
2023-11-16 21:27:59 -07:00
let p: f64 = self.rng.gen();
let ps = &self.params.statements.gen_decl;
2023-11-17 14:50:06 -07:00
let t: BaseType;
let assn: Expr;
if p < ps.gen_integer {
t = BaseType::Int;
assn = self.gen_integer();
2023-11-16 21:27:59 -07:00
} else {
2023-11-17 14:50:06 -07:00
t = BaseType::Real;
assn = self.gen_real();
}
2023-11-16 21:27:59 -07:00
let v = self.gen_variable_quantified(t, Quantifier::Const);
2023-11-17 14:50:06 -07:00
Stat::new_decl(
DeclarationBuilder::default()
2023-11-17 15:46:13 -07:00
.type_ident(self.get_ident_for_type(v.get_base()))
.variable(v)
2023-11-17 14:50:06 -07:00
.assn(Some(assn))
.build()
.unwrap()
)
}
2023-11-17 15:32:12 -07:00
fn gen_typedef(&mut self) -> Stat {
let new_name = self.gen_name();
let (old_name, basetype) = self.typedef_vec
.as_slice()
.choose(&mut self.rng)
.unwrap()
.clone();
2023-11-17 15:46:13 -07:00
self.typedef_map.get_mut(&basetype).unwrap().push(new_name.clone());
2023-11-17 15:32:12 -07:00
self.typedef_vec.push((new_name.clone(), basetype));
Stat::new_typedef(
TypeDefBuilder::default()
.old_name(old_name)
.new_name(new_name)
.basetype(basetype)
.build()
.unwrap()
)
}
fn gen_variable_quantified(&mut self, t: BaseType, q: Quantifier) -> Variable {
VariableBuilder::default()
.type_(t)
.name(self.gen_name())
2023-11-17 14:50:06 -07:00
.quantifier(q)
.build()
.unwrap()
}
2023-11-17 14:50:06 -07:00
fn gen_integer(&mut self) -> Expr {
2023-11-18 00:15:19 -07:00
let p: f64 = self.rng.gen();
let mut ps = &self.params.types.gen_integer;
self.state.int_recursion_depth += 1;
if p < ps.get_instant || self.state.int_recursion_depth >= ps.max_depth {
self.state.int_recursion_depth -= 1;
return Expr::new_literal(self.gen_literal(BaseType::Int));
}
let lhs = self.gen_integer();
let rhs = self.gen_integer();
self.state.int_recursion_depth -= 1;
ps = &self.params.types.gen_integer;
if p < ps.get_instant + ps.expr_add {
Expr::new_binary_op(BinaryOperator::add(lhs, rhs))
} else if p < ps.get_instant + ps.expr_add + ps.expr_sub {
Expr::new_binary_op(BinaryOperator::subtract(lhs, rhs))
} else if p < ps.get_instant + ps.expr_add + ps.expr_sub + ps.expr_mul {
Expr::new_binary_op(BinaryOperator::multiply(lhs, rhs))
} else if p < ps.get_instant + ps.expr_add + ps.expr_sub + ps.expr_mul + ps.expr_div {
Expr::new_binary_op(BinaryOperator::divide(lhs, rhs))
} else {
Expr::new_literal(self.gen_literal(BaseType::Int)) // TODO: this shouldn't be here
}
}
2023-11-17 14:50:06 -07:00
fn gen_real(&mut self) -> Expr {
Expr::new_literal(self.gen_literal(BaseType::Real))
}
fn gen_literal(&mut self, t: BaseType) -> Literal {
match t {
BaseType::Int => {
2023-11-16 21:47:27 -07:00
let i = self.rng_int.sample(&mut self.rng);
Literal::Int(i)
}
2023-11-16 21:24:05 -07:00
BaseType::Real => {
let f = self.rng_float.sample(&mut self.rng);
Literal::Real(f)
}
BaseType::Never => panic!("Attempted to generate literal of type Never"),
BaseType::Unset => panic!("Attempted to generate literal of type Unset"),
}
2023-11-16 16:27:03 -07:00
}
2023-11-17 14:50:06 -07:00
2023-11-17 15:46:13 -07:00
fn get_ident_for_type(&mut self, t: BaseType) -> String {
self.typedef_map[&t].choose(&mut self.rng).unwrap().clone()
}
2023-11-17 14:50:06 -07:00
fn gen_name(&mut self) -> String {
let s = format!("_{}", self.name_counter);
self.name_counter += 1;
s
}
2023-11-16 16:27:03 -07:00
}
impl ToString for AstBuilder {
fn to_string(&self) -> String {
let mut s = format!("// Generated by {} v{}\n",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
);
s.push_str(&self.ast.to_string());
s
}
}
2023-11-16 21:24:05 -07:00
2023-11-16 21:47:27 -07:00
/// Generates values from regions of interest for an integer
///
/// These are concentrated around i32::MIN, 0, and i32::MAX, though any i32 value is possible
struct IntGenerator {
distro_pos: rand_distr::Normal<f32>,
distro_zero: rand_distr::Normal<f32>,
distro_neg: rand_distr::Normal<f32>,
}
impl IntGenerator {
fn new(p: &Params) -> Self {
Self {
distro_pos: rand_distr::Normal::new(0.0, p.dev.int_gen_distro_pos_stddiv).unwrap(),
distro_zero: rand_distr::Normal::new(0.0, 3.0).unwrap(),
distro_neg: rand_distr::Normal::new(0.0, p.dev.int_gen_distro_neg_stddiv).unwrap(),
}
}
}
impl Distribution<i32> for IntGenerator {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> i32 {
let p: f64 = rng.gen();
2023-11-17 14:50:06 -07:00
if p < 0.3 {
2023-11-16 21:47:27 -07:00
i32::MAX - (self.distro_pos.sample(rng).abs() as i32)
2023-11-17 14:50:06 -07:00
} else if p < 0.7 {
2023-11-16 21:47:27 -07:00
self.distro_zero.sample(rng) as i32
} else {
-1 * (i32::MAX - (self.distro_pos.sample(rng).abs() as i32))
}
}
}
2023-11-17 14:50:06 -07:00
2023-11-16 21:24:05 -07:00
/// Generates values from regions of interest for a float
///
/// These are concentrated around f32::MIN, 0, and f32::MAX, though any f32 value is possible
struct FloatGenerator {
distro_pos: rand_distr::Normal<f32>,
distro_zero: rand_distr::Normal<f32>,
distro_neg: rand_distr::Normal<f32>,
}
impl FloatGenerator {
fn new(p: &Params) -> Self {
2023-11-16 21:47:27 -07:00
Self {
2023-11-16 21:24:05 -07:00
distro_pos: rand_distr::Normal::new(1.0, p.dev.float_gen_distro_pos_stddiv).unwrap(),
distro_zero: rand_distr::Normal::new(0.0, 3.0).unwrap(),
distro_neg: rand_distr::Normal::new(1.0, p.dev.float_gen_distro_neg_stddiv).unwrap(),
}
}
}
impl Distribution<f32> for FloatGenerator {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 {
let p: f64 = rng.gen();
if p < 0.33 {
f32::MAX - self.distro_pos.sample(rng).abs()
} else if p < 0.66 {
self.distro_zero.sample(rng)
} else {
-1.0 * (f32::MAX - self.distro_neg.sample(rng).abs())
}
}
}