# Peppermint C89 port This repository root is a clean native C89 implementation of the behavior that is implemented in the original TypeScript Peppermint tree, with no TypeScript, Node.js, Beef, or third-party runtime dependency. Original project: https://github.com/lainq/peppermint ## Build ```sh make ./peppermint smoke.ppm hello ``` The build uses `-std=c89 -pedantic -Wall -Wextra -Wconversion -Wshadow`. The language core is ISO C89; the project-oriented CLI commands use the usual POSIX file APIs (`mkdir`, `stat`, `getcwd`) so `init`/`run`/`list` can create and discover files as the TypeScript CLI does. ## CLI Supported commands: ```sh peppermint run [--file=FILE] [--args ARGS...] peppermint init --name=NAME [--author=AUTHOR] [--license=LICENSE] peppermint list peppermint version peppermint bf --file=FILE [--compile=true] peppermint FILE.ppm [ARGS...] ``` Notes: - `peppermint FILE.ppm [ARGS...]` preserves the first C89 port's direct-file behavior. - `run --file=...` executes a Peppermint source file. - `run` without `--file` reads `.peppermint` in the current directory and uses its `main` string field. - `run --args ...` passes the remaining values to `@argv` / `@argv:N`. - `init` creates `README.md`, `app.ppm`, `tests/test.ppm`, and `.peppermint`. - `list` reads a simple project store. Set `PEPPERMINT_STORE=/path/to/store` to override the default `$HOME/.peppermint/store.json` location. - `version` prints `Peppermint Version 0.0.1[platform]`. - `bf` is a separate Brainfuck runner. With `--compile=true`, it also writes the original Long-language-style output to `dist/test.long`. ## Language behavior Implemented: - `let name := expression` constant bindings. - `let name = expression` mutable bindings. - `name = expression` assignment to existing mutable bindings. - integer and floating-point literals, including unary minus. - quoted strings with `\n`, `\r`, `\t`, and escaped-character handling. - `+`, `-`, `*`, `/`, and `%` with normal arithmetic precedence. - string concatenation with `+` when both operands are strings. - relational operators tokenized by the TypeScript lexer: `==`, `!=`, `>=`, `<=`, `>`, and `<`. They produce `1` for true and `0` for false. - parenthesized expressions. - `#` comments and line-oriented programs. - `@argv`, `@argv:N`, `@env:NAME`, and `@exit`. - robust file/line diagnostics for syntax and runtime errors. ## Upstream gaps and compatibility notes The TypeScript parser in the upstream tree is incomplete: it tokenizes assignment (`=`), constants (`:=`), and relational operators, but only executes arithmetic builtins in practice and does not build a real AST. This C89 port therefore implements the practical behavior those tokens imply instead of claiming byte-for-byte parser parity. Unsupported higher-level semantics such as functions, blocks, imports, conditionals, loops, objects, and a module system are not present in the TypeScript implementation and are intentionally not fabricated here. The TypeScript project store was a JSON file under the compiled CLI directory. A single native executable has no such package directory, so the C89 CLI uses a portable tab-separated project store at `$HOME/.peppermint/store.json` (or `PEPPERMINT_STORE`) while keeping the same user-visible `init`/`list` workflow. ## Tests ```sh ./test.sh ``` The test script rebuilds with strict C89 flags, then checks legacy direct-file execution, command dispatch, expressions, relational operators, mutable vs. constant assignment, builtins, project init/config/list/run behavior, version output, and the Brainfuck runner/compiler command.