From 47608668fa6390b5e10566818bbd863a6bbd8a60 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 18 May 2025 11:50:33 -0400 Subject: [PATCH] cl-embed: Add an example, and a new sample-code (same file) --- .../examples/calculator/expression.cl | 1 + compiler/cl-embed/examples/conculator.rs | 25 +++++ compiler/cl-interpret/src/interpret.rs | 6 +- sample-code/calculator.cl | 95 +++++++++++++++++++ 4 files changed, 123 insertions(+), 4 deletions(-) create mode 120000 compiler/cl-embed/examples/calculator/expression.cl create mode 100644 compiler/cl-embed/examples/conculator.rs create mode 100644 sample-code/calculator.cl diff --git a/compiler/cl-embed/examples/calculator/expression.cl b/compiler/cl-embed/examples/calculator/expression.cl new file mode 120000 index 0000000..85b49cd --- /dev/null +++ b/compiler/cl-embed/examples/calculator/expression.cl @@ -0,0 +1 @@ +../../../../sample-code/calculator.cl \ No newline at end of file diff --git a/compiler/cl-embed/examples/conculator.rs b/compiler/cl-embed/examples/conculator.rs new file mode 100644 index 0000000..194c72c --- /dev/null +++ b/compiler/cl-embed/examples/conculator.rs @@ -0,0 +1,25 @@ +use cl_embed::*; +use repline::{Response, prebaked}; + +fn main() -> Result<(), repline::Error> { + prebaked::read_and("", "calc >", " ? >", |line| { + calc(line).map_err(Into::into) + }) +} + +fn calc(line: &str) -> Result { + let mut env = Environment::new(); + env.bind("line", line); + + let res = conlang!( + mod expression; + use expression::{eval, parse}; + + let (expr, rest) = parse(line.chars(), 0); + eval(expr) + )(&mut env)?; + + println!("{res}"); + + Ok(Response::Accept) +} diff --git a/compiler/cl-interpret/src/interpret.rs b/compiler/cl-interpret/src/interpret.rs index 61e2024..2ca1ff4 100644 --- a/compiler/cl-interpret/src/interpret.rs +++ b/compiler/cl-interpret/src/interpret.rs @@ -162,10 +162,8 @@ impl Interpret for Enum { let idx = idx.interpret(env)?; env.insert(*name, Some(idx)) } - (StructKind::Tuple(_), None) => eprintln!("TODO: Enum-tuple variants: {kind}"), - (StructKind::Struct(_), None) => { - eprintln!("TODO: Enum-struct members: {kind}") - } + (StructKind::Tuple(_), None) => {} + (StructKind::Struct(_), None) => {} _ => eprintln!("Well-formedness error in {self}"), } } diff --git a/sample-code/calculator.cl b/sample-code/calculator.cl new file mode 100644 index 0000000..7ec329c --- /dev/null +++ b/sample-code/calculator.cl @@ -0,0 +1,95 @@ +#!/usr/bin/env -S conlang-run +//! A simple five-function pn calculator + +// TODO: enum constructors in the interpreter +struct Atom(f64); +struct Op(char, [Expr]); + +enum Expr { + Atom(f64), + Op(char, [Expr]), +} + + +// Evaluates an expression +fn eval(expr: Expr) -> isize { + match expr { + Atom(value) => value, + Op('*', [lhs, rhs]) => eval(lhs) * eval(rhs), + Op('/', [lhs, rhs]) => eval(lhs) / eval(rhs), + Op('%', [lhs, rhs]) => eval(lhs) % eval(rhs), + Op('+', [lhs, rhs]) => eval(lhs) + eval(rhs), + Op('-', [lhs, rhs]) => eval(lhs) - eval(rhs), + Op('-', [lhs]) => - eval(lhs), + Op(other, ..rest) => { + panic("ERROR: Unknown operator: " + other) + }, + other => { + println(other); + panic("ERROR: Unknown operation ^") + } + } +} + + +/// 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), + [op, ..rest] => { + parse(rest, pre_bp(op)).map(|lhs| 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| Op(op, [lhs, rhs])); + }; + (lhs, line) +} + +fn number(line: [char]) -> (Expr, [char]) { + let value = 0.0; + while (let [first, ..rest] = line) && (let '0'..='9' = first) { + value = value * 10.0 + (first as f64 - '0' as f64); + line = rest; + }; + (Atom(value), line) +} + +fn space(line: [char]) -> [char] { + match line { + [' ', ..rest] => space(rest), + line => line + } +} + +fn inf_bp(op: char) -> (i32, i32) { + (|x| (2 * x, 2 * x + 1))( + match op { + '*' => 2, + '/' => 2, + '%' => 2, + '+' => 1, + '-' => 1, + _ => -1, + }) +} + +fn pre_bp(op: char) -> i32 { + (|x| 2 * x + 1)( + match op { + '-' => 9, + _ => -1, + }) +}