Skip to content

Commit d00adb9

Browse files
hyperpolymathclaude
andcommitted
fix: add function application, observe, and infer to parser
ExprApp only returned atoms — could not write f(x). Added pipe operator |> for application (LALR1-safe), plus observe(dist, val) and infer METHOD { params } model statement rules. All 177 tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d46fded commit d00adb9

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

compiler/bet-parse/src/grammar.lalrpop

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,26 @@ ExprOpen: Expr = {
306306
// Parallel (brace-delimited)
307307
"parallel" <n:SpannedExprAtom> "{" <body:SpannedExpr> "}" =>
308308
Expr::Parallel(Box::new(n), Box::new(body)),
309+
310+
// Observe: `observe(dist, value)` - condition on observed data
311+
<l:@L> "observe" "(" <dist:SpannedExpr> "," <val:SpannedExpr> ")" <r:@R> =>
312+
Expr::Observe(Box::new(dist), Box::new(val)),
313+
314+
// Infer with parameters: `infer MCMC { steps = 1000, warmup = 500 } model`
315+
"infer" <method:InferMethod> "{" <params:InferParams> "}" <model:SpannedExprAtom> =>
316+
Expr::Infer(InferExpr {
317+
method,
318+
params,
319+
model: Box::new(model),
320+
}),
321+
322+
// Infer without parameters: `infer MCMC model`
323+
"infer" <method:InferMethod> <model:SpannedExprAtom> =>
324+
Expr::Infer(InferExpr {
325+
method,
326+
params: Vec::new(),
327+
model: Box::new(model),
328+
}),
309329
};
310330

311331
// Closed expressions: the operator precedence chain.
@@ -323,6 +343,13 @@ ExprOr: Expr = {
323343
Expr::BinOp(BinOp::Or,
324344
Box::new(Spanned::new(le, Span::new(l as u32, r as u32))),
325345
Box::new(Spanned::new(re, Span::new(l as u32, r as u32)))),
346+
// Pipe application: `x |> f` desugars to `f(x)`.
347+
// Sits at the same level as `||` so `a |> f || b` is `(a |> f) || b`.
348+
<l:@L> <arg:ExprOr> "|>" <f:ExprAnd> <r:@R> =>
349+
Expr::App(
350+
Box::new(Spanned::new(f, Span::new(l as u32, r as u32))),
351+
vec![Spanned::new(arg, Span::new(l as u32, r as u32))],
352+
),
326353
ExprAnd,
327354
};
328355

@@ -548,6 +575,34 @@ RecordTypeField: (Symbol, Spanned<Type>) = {
548575
<name:IDENT> ":" <ty:SpannedType> => (Symbol::intern(&name), ty),
549576
};
550577

578+
// === Inference Helpers ===
579+
580+
InferMethod: InferMethod = {
581+
"MCMC" => InferMethod::MCMC,
582+
"HMC" => InferMethod::HMC,
583+
"SMC" => InferMethod::SMC,
584+
"VI" => InferMethod::VI,
585+
};
586+
587+
// Inference parameters: `steps = 1000, warmup = 500`.
588+
// Uses IDENT ":" SpannedExpr to avoid reduce/reduce with RecordField
589+
// (which uses IDENT "=" SpannedExpr).
590+
InferParams: Vec<(Spanned<Symbol>, Spanned<Expr>)> = {
591+
=> Vec::new(),
592+
<v:InferParamsSep> => v,
593+
<v:InferParamsSep> "," => v,
594+
};
595+
596+
InferParamsSep: Vec<(Spanned<Symbol>, Spanned<Expr>)> = {
597+
<e:InferParam> => vec![e],
598+
<mut v:InferParamsSep> "," <e:InferParam> => { v.push(e); v },
599+
};
600+
601+
InferParam: (Spanned<Symbol>, Spanned<Expr>) = {
602+
<l:@L> <name:IDENT> <r:@R> ":" <val:SpannedExpr> =>
603+
(Spanned::new(Symbol::intern(&name), Span::new(l as u32, r as u32)), val),
604+
};
605+
551606
// === Helpers ===
552607

553608
Ident: String = {

0 commit comments

Comments
 (0)