//! Sample doughlang code struct Expr { Atom (f64), Op (char, [Expr]), } fn execute(expr: Expr) -> f64 { match expr { ExprAtom(value) => value, ExprOp('*', [lhs, rhs]) => execute(lhs) * execute(rhs), ExprOp('/', [lhs, rhs]) => execute(lhs) / execute(rhs), ExprOp('%', [lhs, rhs]) => execute(lhs) % execute(rhs), ExprOp('+', [lhs, rhs]) => execute(lhs) + execute(rhs), ExprOp('-', [lhs, rhs]) => execute(lhs) - execute(rhs), // ExprOp('>', [lhs, rhs]) => (execute(lhs) as u64 >> execute(rhs) as u64) as f64, // ExprOp('<', [lhs, rhs]) => (execute(lhs) as u64 << execute(rhs) as u64) as f64, ExprOp('-', [lhs]) => - execute(lhs), other => { panic("Unknown operation: " + fmt(other)) } } } /// Formats an expression to a string fn fmt_expr(expr: Expr) -> str { match expr { ExprAtom(value) => fmt(value), ExprOp(operator, [lhs, rhs]) => fmt('(', fmt_expr(lhs), ' ', operator, ' ', fmt_expr(rhs), ')'), ExprOp(operator, [rhs]) => fmt(operator, fmt_expr(rhs)), _ => println("Unexpected expr: ", expr), } } /// Prints an expression fn print_expr(expr: Expr) { println(fmt_expr(expr)) } /// Parses expressions fn parse(line: [char], power: i32) -> (Expr, [char]) { fn map((expr, line): (Expr, [char]), f: fn(Expr) -> Expr) -> (Expr, [char]) { (f(expr), line) } line = space(line); let (lhs, line) = match line { ['0'..'9', ..] => number(line), ['(', ..rest] => match parse(rest, Power::None) { (expr, [')', ..rest]) => (expr, rest), (expr, rest) => panic(fmt("Expected ')', got ", expr, ", ", rest)), }, [op, ..rest] => parse(rest, pre_bp(op)).map(|lhs| Expr::Op(op, [lhs])), _ => panic("Unexpected end of input"), }; while let [op, ..rest] = space(line) { let (before, after) = inf_bp(op); if before < power { break; }; (lhs, line) = parse(rest, after).map(|rhs| Expr::Op(op, [lhs, rhs])); }; (lhs, line) }