RepoPilotOpen in app →

flaneur2020/pua-lang

a dialect of The Monkey Programming Language

Mixed

Stale — last commit 1y ago

weakest axis
Use as dependencyMixed

last commit was 1y ago; no tests detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 13 active contributors
  • Distributed ownership (top contributor 36% of recent commits)
  • MIT licensed
Show all 6 evidence items →
  • CI configured
  • Stale — last commit 1y ago
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/flaneur2020/pua-lang?axis=fork)](https://repopilot.app/r/flaneur2020/pua-lang)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/flaneur2020/pua-lang on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: flaneur2020/pua-lang

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/flaneur2020/pua-lang shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 1y ago

  • 13 active contributors
  • Distributed ownership (top contributor 36% of recent commits)
  • MIT licensed
  • CI configured
  • ⚠ Stale — last commit 1y ago
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live flaneur2020/pua-lang repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/flaneur2020/pua-lang.

What it runs against: a local clone of flaneur2020/pua-lang — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in flaneur2020/pua-lang | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 552 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>flaneur2020/pua-lang</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of flaneur2020/pua-lang. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/flaneur2020/pua-lang.git
#   cd pua-lang
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of flaneur2020/pua-lang and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "flaneur2020/pua-lang(\\.git)?\\b" \\
  && ok "origin remote is flaneur2020/pua-lang" \\
  || miss "origin remote is not flaneur2020/pua-lang (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/lib.rs" \\
  && ok "src/lib.rs" \\
  || miss "missing critical file: src/lib.rs"
test -f "src/parser/mod.rs" \\
  && ok "src/parser/mod.rs" \\
  || miss "missing critical file: src/parser/mod.rs"
test -f "src/evaluator/mod.rs" \\
  && ok "src/evaluator/mod.rs" \\
  || miss "missing critical file: src/evaluator/mod.rs"
test -f "src/ast.rs" \\
  && ok "src/ast.rs" \\
  || miss "missing critical file: src/ast.rs"
test -f "src/lexer/mod.rs" \\
  && ok "src/lexer/mod.rs" \\
  || miss "missing critical file: src/lexer/mod.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 552 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~522d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/flaneur2020/pua-lang"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

pua-lang is a Rust-implemented interpreter for a Monkey-based programming language with intentionally satirical Chinese keywords replacing standard syntax. It implements a complete interpreter pipeline (lexer → parser → evaluator) that executes dynamically-typed code with first-class functions, closures, arrays, and hash maps, plus a WebAssembly playground (web/) exposing the interpreter to browsers. Single-crate Rust binary: src/lexer/mod.rs tokenizes input, src/parser/mod.rs builds an AST (src/ast.rs), src/evaluator/mod.rs executes via direct tree-walking evaluation using src/evaluator/object.rs (runtime object model) and src/evaluator/builtins.rs (built-in functions). Separate WASM target in src/wasm/main.rs. Web playground in web/ (Node.js + HTML/CSS) calls the compiled WASM binary.

👥Who it's for

Programming language enthusiasts and interpreter learners studying how to build an evaluator-based interpreter in Rust; contributors interested in esoteric language design or educational compilers; developers wanting to understand the lexer-parser-evaluator architecture without the complexity of a compiled language like Rust itself.

🌱Maturity & risk

Actively developed but experimental: single maintainer (flaneur2020), no visible test suite in file listing, CI/CD pipeline in place (.circleci/, .github/workflows/), but README admits WASM I/O redirection doesn't work. Not production-ready; suitable for learning and curiosity projects.

Single-maintainer risk is significant. Minimal dependencies (rustyline, unicode-xid, unicode-normalization) reduce supply-chain attack surface, but no visible error recovery or comprehensive test suite increases the risk of silent semantic bugs in the evaluator. WASM target is acknowledged as partially broken (I/O streams). No stability guarantees or versioning discipline evident.

Active areas of work

No recent commit data visible in file listing, so active development status unclear. The README and docs/ suggest the core language is largely feature-complete (if-else, loops, functions, arrays, hashes working), but known issues exist: WASM I/O doesn't work, and some syntax features (Array/Hash keyword naming) are experimental.

🚀Get running

git clone https://github.com/flaneur2020/pua-lang.git
cd pua-lang
make repl

Or to build the WASM playground locally, see web/package.json (Node.js required); npm install && npm run dev (inferred from package.json structure).

Daily commands: REPL: make repl (uses Makefile target, requires cargo). WASM locally: cd web && npm install && npm run dev (serves http://localhost:???; exact port in web/package.json). Execute a file: (no evidence of file input in bin/main.rs; REPL-only for native binary).

🗺️Map of the codebase

  • src/lib.rs — Library entry point that exports core modules (lexer, parser, evaluator, ast); essential for understanding the public API and module organization.
  • src/parser/mod.rs — Parser implementation that converts tokens into an AST; foundational for language syntax and expression handling.
  • src/evaluator/mod.rs — Core interpreter/evaluator that executes the AST; implements language semantics and control flow.
  • src/ast.rs — Abstract Syntax Tree definitions; defines all node types that the parser produces and evaluator consumes.
  • src/lexer/mod.rs — Tokenizer that converts source code into tokens; the first stage of the compilation pipeline.
  • src/evaluator/object.rs — Runtime object system and value representation; defines how all runtime values (integers, strings, functions, etc.) are stored and manipulated.
  • src/bin/main.rs — REPL entry point for interactive development; demonstrates end-to-end usage of the lexer, parser, and evaluator.

🧩Components & responsibilities

  • Lexer (Rust iterators, unicode-xid, unicode-normalization) — Converts raw source code into a stream of tokens; handles string escape sequences and Unicode identifiers.
    • Failure mode: Invalid token sequence (e.g., unclosed string) halts parsing with an error.
  • Parser (Recursive descent, precedence climbing) — Consumes tokens and builds an Abstract Syntax Tree; enforces operator precedence and syntax rules.
    • Failure mode: Parse errors (unexpected token, missing operator, etc.) terminate evaluation.
  • **** — undefined

🛠️How to make changes

Add a new built-in function

  1. Define the function in the builtins module; add a new arm to the match statement in the 'call_builtin' function. (src/evaluator/builtins.rs)
  2. Register the function name in the evaluator's identifier resolution to map it to the builtin. (src/evaluator/mod.rs)
  3. Return an Object::Builtin variant wrapping your function logic; handle argument validation and type checking. (src/evaluator/object.rs)

Add a new language operator or expression type

  1. Define the new token type in the Token enum. (src/token.rs)
  2. Extend the lexer to recognize the token from source code. (src/lexer/mod.rs)
  3. Add the AST node variant for the new expression or operator. (src/ast.rs)
  4. Implement parsing logic in the parser, respecting operator precedence. (src/parser/mod.rs)
  5. Implement evaluation logic in the evaluator to handle the new AST node. (src/evaluator/mod.rs)

Add a new data type to the language

  1. Create a new Object variant in the enum (e.g., Object::MyType). (src/evaluator/object.rs)
  2. Implement Display, Hash, Eq, Clone as needed for the new type. (src/evaluator/object.rs)
  3. Update the parser to recognize literals of this type if applicable. (src/parser/mod.rs)
  4. Add evaluation logic for constructing and manipulating instances in the evaluator. (src/evaluator/mod.rs)
  5. Update the formatter to pretty-print the new type. (src/formatter/mod.rs)

🔧Why these technologies

  • Rust — Memory safety without garbage collection; high performance for an interpreter; enables straightforward WASM compilation for browser playground.
  • Recursive descent parser with precedence climbing — Simple to understand and extend for educational purposes (mirrors the Monkey interpreter book); natural fit for expression precedence in a small language.
  • Tree-walking interpreter (AST-based) — Simplicity and clarity; no bytecode compilation stage needed; suitable for a language designed for learning.
  • WebAssembly (wasm32-unknown-unknown) — Enables zero-installation browser playground; Rust's excellent WASM tooling; reaches users without build setup.
  • Webpack + CodeMirror — Standard modern frontend tooling; CodeMirror provides syntax highlighting and editor UX for the playground.

⚖️Trade-offs already made

  • Tree-walking interpreter instead of bytecode/VM

    • Why: Reduces implementation complexity and aligns with educational goals.
    • Consequence: Slower performance than compiled or bytecode-interpreted languages; no optimization passes.
  • Immutable environments with clone-on-write

    • Why: Simplicity and correctness in closures and nested scopes; avoids mutation bugs.
    • Consequence: Higher memory usage and allocation overhead compared to mutable arena-based environments.
  • No I/O redirection in WASM playground

    • Why: wasm32-unknown-unknown has no OS I/O primitives; architectural mismatch between server and browser environments.
    • Consequence: Builtin functions like puts() do not output to the REPL in the playground (acknowledged in README).
  • Statically typed tokens and AST nodes

    • Why: Type safety and compile-time guarantees in the implementation.
    • Consequence: Rust's pattern matching provides exhaustiveness checking; refactoring is safer but sometimes verbose.

🚫Non-goals (don't propose these)

  • Does not support I/O in WASM playground (acknowledged limitation; no stdout redirection in browser).
  • Does not implement compilation to bytecode or a JIT; strictly tree-walking interpretation.
  • Does not provide a standard library beyond built-in functions; limited to len, push, puts, type, etc.
  • Does not support modules or imports; single-file execution only.
  • Not intended for production use; designed as a learning tool and dialect of Monkey.

🪤Traps & gotchas

No file input: src/bin/main.rs provides a REPL but no CLI argument to execute .pua files; you must paste code into the REPL or modify main.rs. WASM I/O broken: README explicitly warns that output streams (puts) don't work in wasm32-unknown-unknown target due to Rust's lack of I/O redirection there. Unicode complexity: lexer/unescape.rs handles Rust-style string escapes, but XID + emoji identifiers may have subtle bugs (no tests visible). No error recovery: parser likely panics or returns opaque error on syntax error; no line/column diagnostics evident. Shared mutable state risk: src/evaluator/env.rs uses RefCell for scopes; potential for runtime panics if borrow rules violated.

🏗️Architecture

💡Concepts to learn

  • Tree-walking interpreter — pua-lang executes by recursively traversing the AST directly (no bytecode or JIT); understanding this pattern is essential to following src/evaluator/mod.rs logic
  • Recursive descent parsing — src/parser/mod.rs uses hand-written recursive functions (one per grammar rule); no parser generator. Pratt parsing handles operator precedence.
  • Lexical scoping and closures — src/evaluator/env.rs implements nested scopes via parent pointers; understanding closure semantics (captured variables in src/evaluator/object.rs::Function) is critical
  • Unicode identifier support (UAX #31 + XID) — src/lexer/mod.rs and src/lexer/unescape.rs use the unicode-xid crate to allow emoji and Chinese characters as valid identifiers; non-ASCII design choice is core to pua-lang's identity
  • Environment (symbol table) management — src/evaluator/env.rs uses RefCell-wrapped HashMap for runtime variable bindings; Rust's interior mutability pattern (RefCell) enables mutable scope in an otherwise immutable tree walk
  • Truthy/falsy and object tagging — src/evaluator/object.rs defines a tagged union (enum) for runtime values; the Object type is the sole runtime representation of all Monkey values (no class hierarchy, no vtables)
  • WASM FFI and JavaScript interop — src/wasm/main.rs exports Rust functions to WebAssembly; the web/ frontend calls these via wasm-bindgen (implied from structure). Understanding wasm binary interfaces is needed to debug I/O issues
  • wadackel/rs-monkey-lang — Direct predecessor: the original Rust implementation of Monkey that pua-lang forks and extends with Chinese keywords and Unicode identifiers
  • crafting-interpreters/crafting-interpreters — Educational resource: pua-lang's design philosophy mirrors 'Writing An Interpreter In Go' (the book that inspired Monkey), with hand-written lexer/parser/evaluator pattern
  • rust-lang/rust — Implementation language and reference for idiomatic Rust patterns (especially environment/scope management in src/evaluator/env.rs)
  • tree-sitter/tree-sitter — Alternative parsing approach (incremental parsing via C library bindings); if pua-lang ever needed better error recovery or IDE support, tree-sitter would be relevant
  • gluon-lang/gluon — Related Rust-based language with interpreter; different design (statically typed, Hindley-Milner), but similar single-language-in-one-repo architecture

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for src/lexer/unescape.rs

The unescape module handles string escape sequences but has no visible test coverage. This is critical for correctness since escape sequence parsing is error-prone. Adding tests would catch regressions and document expected behavior for contributors.

  • [ ] Create tests/lexer_unescape_test.rs with test cases for common escapes (\n, \t, \r, \u, \x)
  • [ ] Add edge case tests for invalid escape sequences and malformed unicode
  • [ ] Test round-trip behavior: unescape → string → display
  • [ ] Run cargo test to verify coverage and integrate with CI

Add integration tests for WASM playground build in GitHub Actions

The repo has a web playground and wasm binary target (src/wasm/main.rs) but the .github/workflows/rust.yml likely only tests the CLI. Adding a dedicated workflow would catch WASM-specific breakage before deployment to the hosted playground.

  • [ ] Extend .github/workflows/rust.yml to add a job that runs cargo build --target wasm32-unknown-unknown --features wasm
  • [ ] Add wasm-pack or wasm-bindgen setup if needed for the web/ build integration
  • [ ] Verify the web/ package.json build script runs successfully in CI
  • [ ] Document WASM build requirements in README.md#Development section

Add missing formatter tests in tests/ directory

The src/formatter/mod.rs module handles code formatting but there's no visible test suite. A formatter is user-facing and regressions are visible to end-users. Tests would validate formatting behavior across language constructs (functions, conditionals, loops).

  • [ ] Create tests/formatter_test.rs with test cases for basic constructs (if/else, functions, let statements)
  • [ ] Add tests for edge cases like nested structures and operator precedence formatting
  • [ ] Test round-trip: parse → format → parse gives equivalent AST
  • [ ] Integrate tests into CI and document in CONTRIBUTING guidelines

🌿Good first issues

  • Add file input to CLI binary (src/bin/main.rs): Currently only REPL works natively. Modify main.rs to accept a filename argument, read it, and execute. Unblocks users wanting to write .pua files instead of typing in REPL.
  • Write integration tests for evaluator edge cases: No visible test suite in src/. Add tests in tests/ or #[cfg(test)] blocks testing arithmetic, function closure semantics, hash/array indexing, error cases. Catch silent semantic bugs.
  • Document the satire mapping clearly in src/token.rs or docs/: README has a table mapping Monkey → pua-lang keywords, but the source code itself has no comments explaining why (e.g. 三七五 = 3.75 = passing grade). Add rustdoc comments mapping each keyword to its Chinese meaning and performance-review context.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 513b7cf — Merge pull request #77 from lwz23/master (flaneur2020)
  • 1e8e7fe — replace Vec::from_raw_parts with ptr::write_bytes (lwz23)
  • cbaf8e2 — Update README.md (flaneur2020)
  • 4bcb9e3 — Merge pull request #75 from meloalright/master (flaneur2020)
  • b2a77f8 — + dot access getter for hash (meloalright)
  • b998b65 — Merge pull request #74 from meloalright/master (flaneur2020)
  • e34d9b8 — + keyword means break the loop and unit test (meloalright)
  • 2364c59 — Add the unit test code for break and continue statements (meloalright)
  • 152e459 — + break statement and continue statement (meloalright)
  • 0fdbcbc — tune fibonacci function in readme (flaneur2020)

🔒Security observations

The pua-lang codebase demonstrates a reasonably secure foundation as a language interpreter implementation. The primary concerns are: (1) an outdated rustyline dependency (8.0.0 from 2020) which should be updated to the latest version; (2) potential XSS vulnerabilities in the web playground if user code output is not properly sanitized; (3) missing security headers in the web configuration; and (4) lack of documented input validation limits in the parser/lexer. The interpreter itself (Rust-based core) is relatively safe from memory-safety vulnerabilities due to Rust's type system. No hardcoded secrets, SQL injection risks, or obvious infrastructure misconfigurations were detected in the provided files.

  • Medium · Outdated Dependency: rustyline — Cargo.toml - rustyline = { version = "8.0.0", optional = true }. The rustyline dependency is pinned to version 8.0.0, which was released in 2020. This version may contain known security vulnerabilities that have been patched in newer releases. Outdated dependencies can introduce security risks. Fix: Update rustyline to the latest stable version (currently 13.x+). Review the changelog for security fixes and breaking changes before upgrading.
  • Low · Potential XSS Risk in Web Playground — web/src/js/editor/share.js and web/src/js/editor/snippet.js. The web playground (web/src/js/editor/share.js) may handle user input or code snippets that could be rendered without proper sanitization. JavaScript-based code editors can be vulnerable to XSS if code output is rendered unsafely. Fix: Audit the share.js and snippet.js files to ensure all user-generated content and code snippets are properly escaped or sanitized before rendering. Use textContent instead of innerHTML where possible.
  • Low · Missing Security Headers in Web Configuration — web/webpack.config.js and web/src/index.html. The webpack configuration (web/webpack.config.js) and HTML entry point (web/src/index.html) do not appear to configure security headers (CSP, X-Frame-Options, etc.). This could expose the web playground to XSS and clickjacking attacks. Fix: Implement Content Security Policy (CSP) headers, X-Frame-Options, X-Content-Type-Options, and other security headers in the web server configuration or via webpack plugins. Use a security header middleware in any backend serving the playground.
  • Low · No Input Validation Documentation — src/lexer/mod.rs and src/parser/mod.rs. The lexer (src/lexer/mod.rs) and parser (src/parser/mod.rs) do not have visible bounds checking or input validation documentation. Large or malicious inputs could potentially cause DoS or stack overflow attacks. Fix: Implement input size limits and recursion depth limits in the lexer and parser. Document maximum supported code lengths and complexity bounds.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · flaneur2020/pua-lang — RepoPilot