1use crate::builtins::Builtin;
10use probl_syntax::Span;
11use probl_syntax::ast::{BinOp, UnOp};
12
13pub type SlotId = u32;
14pub type FnId = u32;
15pub type StmtId = u32;
16
17pub const MAIN: FnId = 0;
19
20pub const TEMP: &str = "(temporary)";
23
24#[derive(Debug)]
25pub struct Program {
26 pub functions: Vec<Function>,
28 pub reports: Vec<ReportSite>,
29 pub records: Vec<RecordType>,
30 pub enums: Vec<EnumType>,
31 pub inputs: Vec<Input>,
33 pub settings: Settings,
34 pub stmt_count: u32,
36}
37
38#[derive(Clone, Debug, PartialEq)]
42pub struct Input {
43 pub name: String,
45 pub path: String,
48 pub format: DataFormat,
49 pub ty: TypeSpec,
51 pub span: Span,
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub enum DataFormat {
57 Csv,
58 Json,
59 Lines,
60}
61
62impl Program {
63 pub fn main(&self) -> &Function {
64 &self.functions[MAIN as usize]
65 }
66}
67
68#[derive(Clone, Debug, PartialEq)]
69pub struct Settings {
70 pub mode: Mode,
71 pub mode_span: Option<Span>,
73 pub epsilon: f64,
76 pub max_iterations: u64,
77 pub max_worlds: usize,
78 pub on_error: Option<FailureMode>,
81 pub integrate: Option<f64>,
85}
86
87pub const DEFAULT_TOLERANCE: f64 = 1e-9;
89
90impl Default for Settings {
91 fn default() -> Settings {
92 Settings {
93 mode: Mode::Auto,
94 mode_span: None,
95 epsilon: 1e-12,
96 max_iterations: 10_000_000,
97 max_worlds: 10_000_000,
98 on_error: None,
99 integrate: None,
100 }
101 }
102}
103
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
107pub enum FailureMode {
108 Total,
110 Partial,
112}
113
114impl FailureMode {
115 pub fn name(self) -> &'static str {
116 match self {
117 FailureMode::Total => "total",
118 FailureMode::Partial => "partial",
119 }
120 }
121}
122
123#[derive(Clone, Debug, PartialEq)]
124pub enum Mode {
125 Auto,
126 Enumerate,
127 Beam { worlds: u64 },
128 Sample { runs: u64, seed: u64 },
129 Particles { runs: u64, seed: u64 },
130}
131
132impl Mode {
133 pub fn name(&self) -> &'static str {
134 match self {
135 Mode::Auto => "auto",
136 Mode::Enumerate => "enumerate",
137 Mode::Beam { .. } => "beam",
138 Mode::Sample { .. } => "sample",
139 Mode::Particles { .. } => "particles",
140 }
141 }
142}
143
144#[derive(Clone, Debug)]
145pub struct ReportSite {
146 pub label: String,
147 pub key_label: Option<String>,
149 pub kind: ReportKind,
150 pub span: Span,
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq)]
155pub enum ReportKind {
156 Once,
158 PerKey,
161 PerVisit,
163}
164
165#[derive(Clone, Debug)]
166pub struct RecordType {
167 pub name: String,
168 pub fields: Vec<RecordField>,
170 pub span: Span,
171}
172
173#[derive(Clone, Debug)]
174pub struct RecordField {
175 pub name: String,
176 pub ty: TypeSpec,
177 pub span: Span,
178}
179
180#[derive(Clone, Debug)]
181pub struct EnumType {
182 pub name: String,
183 pub variants: Vec<String>,
184}
185
186#[derive(Clone, Copy, Debug, PartialEq, Eq)]
187pub enum FnKind {
188 Main,
189 Named,
190 Lambda,
191 Simulate,
192}
193
194#[derive(Clone, Debug)]
195pub struct Function {
196 pub name: String,
197 pub kind: FnKind,
198 pub span: Span,
199 pub n_params: u32,
201 pub captures: Vec<Capture>,
203 pub slots: Vec<SlotInfo>,
204 pub body: Block,
205 pub effects: Effects,
206}
207
208#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
211pub struct Effects {
212 pub observes: bool,
214 pub prints: bool,
216}
217
218impl Function {
219 pub fn n_slots(&self) -> usize {
220 self.slots.len()
221 }
222}
223
224#[derive(Clone, Debug)]
227pub struct UpdateCheck {
228 pub ty: TypeSpec,
231 pub args: Option<Vec<Option<TypeSpec>>>,
235}
236
237#[derive(Clone, Copy, Debug, PartialEq, Eq)]
238pub struct Capture {
239 pub slot: SlotId,
241 pub source: CaptureSource,
242 pub for_values: bool,
246}
247
248#[derive(Clone, Copy, Debug, PartialEq, Eq)]
249pub enum CaptureSource {
250 Global(SlotId),
252 Parent(SlotId),
254}
255
256#[derive(Clone, Debug)]
257pub struct SlotInfo {
258 pub name: String,
259 pub span: Span,
260}
261
262#[derive(Clone, Debug, Default)]
263pub struct Block {
264 pub stmts: Vec<Stmt>,
265}
266
267#[derive(Clone, Debug)]
268pub struct Stmt {
269 pub id: StmtId,
270 pub span: Span,
271 pub kind: StmtKind,
272}
273
274#[derive(Clone, Debug)]
275pub enum StmtKind {
276 Set {
278 place: Place,
279 value: Expr,
280 },
281 Update {
286 place: Place,
287 value: Expr,
288 check: Option<UpdateCheck>,
289 },
290 Draw {
292 place: Place,
293 dist: Expr,
294 },
295 Take {
297 place: Place,
298 bag: Place,
299 },
300 Call {
302 dest: Place,
303 callee: Callee,
304 args: Vec<Expr>,
305 },
306 If {
307 cond: Expr,
308 then: Block,
309 otherwise: Block,
310 },
311 Chance {
314 arms: Vec<(Expr, Block)>,
315 otherwise: Option<Block>,
316 exhaustive: bool,
317 },
318 Loop {
322 body: Block,
323 bounded: bool,
324 },
325 Break,
326 Continue,
327 Return(Expr),
328 Observe {
329 value: Expr,
330 from: Option<Expr>,
331 },
332 Report {
333 site: u32,
334 value: Expr,
335 key: Option<Expr>,
336 },
337 Fail {
339 message: String,
340 },
341 Check {
343 slot: SlotId,
344 ty: TypeSpec,
345 },
346 Try {
350 body: Block,
351 catches: Vec<Catch>,
352 },
353}
354
355#[derive(Clone, Debug)]
357pub struct Catch {
358 pub fault: Option<Fault>,
360 pub body: Block,
361}
362
363impl Catch {
364 pub fn catches(&self, fault: Option<Fault>) -> bool {
365 fault.is_some() && (self.fault.is_none() || self.fault == fault)
366 }
367}
368
369#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
375pub enum Fault {
376 DivisionByZero,
378 DomainError,
381 IndexOutOfBounds,
383 MissingKey,
385 EmptyCollection,
387 ConversionError,
389 NumericOverflow,
392}
393
394impl Fault {
395 pub const ALL: [Fault; 7] = [
396 Fault::DivisionByZero,
397 Fault::DomainError,
398 Fault::IndexOutOfBounds,
399 Fault::MissingKey,
400 Fault::EmptyCollection,
401 Fault::ConversionError,
402 Fault::NumericOverflow,
403 ];
404
405 pub fn name(self) -> &'static str {
407 match self {
408 Fault::DivisionByZero => "DivisionByZero",
409 Fault::DomainError => "DomainError",
410 Fault::IndexOutOfBounds => "IndexOutOfBounds",
411 Fault::MissingKey => "MissingKey",
412 Fault::EmptyCollection => "EmptyCollection",
413 Fault::ConversionError => "ConversionError",
414 Fault::NumericOverflow => "NumericOverflow",
415 }
416 }
417
418 pub fn from_name(name: &str) -> Option<Fault> {
419 Fault::ALL.into_iter().find(|f| f.name() == name)
420 }
421}
422
423#[derive(Clone, Debug, PartialEq)]
425pub enum TypeSpec {
426 Int,
427 Float,
428 Complex,
429 Prob,
430 Bool,
431 Str,
432 Date,
433 Unit,
434 Function,
435 List(Box<TypeSpec>),
436 Map(Box<TypeSpec>, Box<TypeSpec>),
437 Bag(Box<TypeSpec>),
438 Dist(Box<TypeSpec>),
439 Record(u32),
440 Enum(u32),
441 AnonRecord(Vec<(String, TypeSpec)>),
442}
443
444impl TypeSpec {
445 pub fn describe(&self, program: &Program) -> String {
447 self.describe_in(&program.records, &program.enums)
448 }
449
450 pub fn describe_in(&self, records: &[RecordType], enums: &[EnumType]) -> String {
452 let describe = |t: &TypeSpec| t.describe_in(records, enums);
453 match self {
454 TypeSpec::Int => "int".into(),
455 TypeSpec::Float => "float".into(),
456 TypeSpec::Complex => "complex".into(),
457 TypeSpec::Prob => "prob".into(),
458 TypeSpec::Bool => "bool".into(),
459 TypeSpec::Str => "str".into(),
460 TypeSpec::Date => "date".into(),
461 TypeSpec::Unit => "()".into(),
462 TypeSpec::Function => "fn".into(),
463 TypeSpec::List(t) => format!("list[{}]", describe(t)),
464 TypeSpec::Map(k, v) => format!("map[{}, {}]", describe(k), describe(v)),
465 TypeSpec::Bag(t) => format!("bag[{}]", describe(t)),
466 TypeSpec::Dist(t) => format!("dist[{}]", describe(t)),
467 TypeSpec::Record(r) => records[*r as usize].name.clone(),
468 TypeSpec::Enum(e) => enums[*e as usize].name.clone(),
469 TypeSpec::AnonRecord(fields) => {
470 let fields: Vec<String> = fields.iter().map(|(n, t)| format!("{n}: {}", describe(t))).collect();
471 format!("{{ {} }}", fields.join(", "))
472 }
473 }
474 }
475}
476
477#[derive(Clone, Debug)]
479pub struct Place {
480 pub slot: SlotId,
481 pub path: Vec<PathElem>,
482}
483
484impl Place {
485 pub fn slot(slot: SlotId) -> Place {
486 Place { slot, path: Vec::new() }
487 }
488}
489
490#[derive(Clone, Debug)]
491pub enum PathElem {
492 Field(String),
493 Index(Expr),
494}
495
496#[derive(Clone, Debug)]
497pub enum Callee {
498 Fn { func: FnId, capture_args: Vec<SlotId> },
501 Value(Expr, Vec<String>),
503}
504
505#[derive(Clone, Debug)]
506pub struct Expr {
507 pub kind: ExprKind,
508 pub span: Span,
509}
510
511#[derive(Clone, Debug)]
512pub enum ExprKind {
513 Lit(Lit),
514 Slot(SlotId),
515 Unary(UnOp, Box<Expr>),
516 Binary(BinOp, Box<Expr>, Box<Expr>),
519 List(Vec<Expr>),
520 Map(Vec<(Expr, Expr)>),
521 Record {
522 ty: Option<u32>,
523 fields: Vec<(String, Expr)>,
524 },
525 Field(Box<Expr>, String),
526 Index(Box<Expr>, Box<Expr>),
527 With(Box<Expr>, Vec<(String, Expr)>),
528 Builtin {
529 func: Builtin,
530 args: Vec<Expr>,
531 named: Vec<(String, Expr)>,
532 },
533 Closure {
535 func: FnId,
536 capture_args: Vec<SlotId>,
537 },
538 Simulate {
540 func: FnId,
541 capture_args: Vec<SlotId>,
542 },
543 Bind {
549 value: Box<Expr>,
550 globals: Vec<(SlotId, SlotId)>,
551 },
552 Interp(Vec<InterpPart>),
553 Input(u32),
555}
556
557#[derive(Clone, Debug)]
558pub enum InterpPart {
559 Lit(String),
560 Expr(Expr),
561}
562
563#[derive(Clone, Debug, PartialEq)]
564pub enum Lit {
565 Builtin(Builtin),
566 Unit,
567 Bool(bool),
568 Int(probl_number::Integer),
569 Float(f64),
570 FloatConstant(f64),
573 Prob(f64),
574 Str(String),
575 Dice {
576 count: u32,
577 sides: u32,
578 },
579 Enum {
580 ty: u32,
581 variant: u32,
582 },
583}