Files
legis/examples/calculator.lgi
claude 33bd4a78ff Phase 0+1: workspace scaffolding and lexer
Stand up the Cargo workspace for the Legis compiler and implement the lexer,
the first stage of the pipeline described in the v1.0 specification.

- legis-diag: Diagnostic type plus the banned-jargon guard that the whole
  toolchain is tested against (no forbidden programming term may appear in any
  message). Whole-word, underscore-aware matching so quoted code identifiers
  are not false positives.
- legis-lexer: logos-based lexer covering the full token list. Numbers carry no
  sign (unary minus is a parser concern), text and multi-line text values,
  doc comments preserved while line/block comments are dropped, longest-match
  tags and operators, plain-English lexer errors.
- legis-cli: the `legis` binary with a `tokens` inspection command.
- examples/calculator.lgi: the specification's reference program, the milestone
  the pipeline is built toward.
- PLAN.md: phased implementation roadmap (LLVM-from-start).

18 tests pass; fmt and clippy clean. The lexer tokenizes the reference
calculator with no errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 16:05:27 -05:00

147 lines
3.5 KiB
Plaintext

use library std.console;
use library std.text;
/// The mathematical operation the user has chosen.
choices Operation {
Add;
Subtract;
Multiply;
Divide;
}
/// Asks the user which operation to perform.
function choose_operation() returns Result<Operation, Text> {
std.console.println("");
std.console.println("Choose an operation");
std.console.println(" + Add");
std.console.println(" - Subtract");
std.console.println(" * Multiply");
std.console.println(" / Divide");
std.console.print("> ");
let response = pass up std.console.read_line()
.or_fail("Could not read from the keyboard");
match std.text.trim(response) {
is "+": give back Operation.Add;
is "-": give back Operation.Subtract;
is "*": give back Operation.Multiply;
is "/": give back Operation.Divide;
otherwise:
give back fail("Please enter +, -, *, or /");
}
}
/// Asks the user for a decimal number.
function choose_number(prompt: Text) returns Result<Decimal, Text> {
std.console.print("{prompt}: ");
let response = pass up std.console.read_line()
.or_fail("Could not read from the keyboard");
let cleaned = std.text.trim(response);
when std.text.parse<Decimal>(cleaned) {
succeeds with number:
give back number;
fails:
give back fail("'{cleaned}' is not a valid number");
}
}
/// Carries out the calculation.
/// Division by zero gives back a failure rather than crashing.
pure function calculate(
first_number: Decimal,
operation: Operation,
second_number: Decimal
) returns Result<Decimal, Text> {
match operation {
is Operation.Add:
give back first_number + second_number;
is Operation.Subtract:
give back first_number - second_number;
is Operation.Multiply:
give back first_number * second_number;
is Operation.Divide:
if second_number == 0.0 {
give back fail("Division by zero is not allowed");
}
give back first_number / second_number;
}
}
/// Runs one calculation and gives back whether to keep going.
function run_calculator() returns Bool {
let first_number = when choose_number("First number") {
succeeds with value: value;
fails with problem: {
std.console.println(problem);
give back true;
}
};
let chosen_operation = when choose_operation() {
succeeds with value: value;
fails with problem: {
std.console.println(problem);
give back true;
}
};
let second_number = when choose_number("Second number") {
succeeds with value: value;
fails with problem: {
std.console.println(problem);
give back true;
}
};
when calculate(first_number, chosen_operation, second_number) {
succeeds with answer: {
let symbol = match chosen_operation {
is Operation.Add: "+";
is Operation.Subtract: "-";
is Operation.Multiply: "*";
is Operation.Divide: "/";
};
std.console.println("");
std.console.println("{first_number} {symbol} {second_number} = {answer}");
}
fails with reason:
std.console.println("Problem: {reason}");
}
std.console.println("");
std.console.print("Another calculation? (y/n): ");
let response = when std.console.read_line() {
succeeds with value: std.text.trim(value).to_lower();
fails: give back false;
};
give back response == "y" || response == "yes";
}
/// Entry point — runs the calculator until the user says to stop.
function main() {
std.console.println("Legis Calculator");
std.console.println("----------------");
vary running = true;
repeat while running {
running = run_calculator();
}
std.console.println("");
std.console.println("Goodbye.");
}