═══════════════════════════════════════════════════════════════════════════════
  ALZ PROGRAMMING LANGUAGE — MASTER INSTRUCTIONS
  Version: 0.6.0
  Author:  ALZ TECH
  Purpose: Complete guide for any AI or developer continuing this project
═══════════════════════════════════════════════════════════════════════════════

  READ THIS ENTIRE FILE BEFORE TOUCHING ANY CODE.

───────────────────────────────────────────────────────────────────────────────
  SECTION 1 — WHAT IS ALZ?
───────────────────────────────────────────────────────────────────────────────

  ALZ is a beginner-friendly programming language.

  - Files use the .alz extension
  - Transpiles to JavaScript, runs on Node.js
  - Reads like plain English
  - Everything built in — no hunting for packages
  - Installed via:  npm install -g alz-lang
  - Run via:        alz myfile.alz

  The npm package is named "alz-lang" because "alz" was already taken
  on npm by an empty package. But after installing alz-lang, the command
  the user types is just "alz". The bin field in package.json handles this.

  ALZ does NOT have its own runtime or VM.
  It compiles .alz → JavaScript → Node.js executes it.
  Think of it like TypeScript — compiles to JS, Node runs it.

  CORE PHILOSOPHY (never break these):
  - One way to do everything
  - Read like English, run like a machine
  - No setup — just write and run
  - Errors in plain English
  - Everything built in
  - No type declarations

───────────────────────────────────────────────────────────────────────────────
  SECTION 2 — PERMANENT DECISIONS (do not reverse these)
───────────────────────────────────────────────────────────────────────────────

  DECISION 1: JavaScript only. No Python backend.
    Every feature would require double work forever.
    Node.js runs everywhere — Linux, Mac, Windows, Termux.
    Python backend can be added later if users ask for it.

  DECISION 2: No database keywords.
    Keywords like save/load/remove/add caused parser bugs
    because they collide with common function names.
    DB access is stdlib method calls only:
      db.save("users", { name: "Sara" })
      db.find("users", { name: "Sara" })
      db.all("users")
      db.remove("users", { name: "Sara" })
      db.update("users", { name: "Sara" }, { age: 26 })
    No new keywords. Parser never touches db. Just function calls.
    Storage: JSON files in .alzdata/ — no SQL, no setup.

  DECISION 3: No frontend syntax before v2.0.
    page/title/button/input postponed until backend is solid.
    Priority: CLI tools, backend APIs, bots, automation.

  DECISION 4: Real lexer → parser → AST. Never regex replacements.
    Regex breaks as soon as someone puts a keyword inside a string.
    The pipeline is 3 files and works. Never replace with shortcuts.

  DECISION 5: Keywords must not be common words.
    Words like add, remove, update, save, load, set, from, all
    must NOT be standalone keywords — they collide with function names.
    Use multi-word keywords or keep them as stdlib method names.

  DECISION 6: "show" is a backward-compat alias for "print".
    The lexer converts "show" → "print" token at lex time.
    "print" is the official keyword. "show" still works silently.
    Do not add "show" back as a separate keyword.

  DECISION 7: Keep "else if" (two words). Do not add "elif".
    "else if" reads more naturally than "elif" for beginners.
    The lexer emits "else if" as a single KEYWORD token already.

  DECISION 8: "is"/"isnt" are the ALZ way. "=="/"!=" also work.
    Document "is"/"isnt" as primary in all examples.
    Keep "=="/"!=" working for developers coming from other languages.

───────────────────────────────────────────────────────────────────────────────
  SECTION 3 — FILE STRUCTURE
───────────────────────────────────────────────────────────────────────────────

  alz/
  ├── bin/
  │   └── alz                  ← CLI entry point (the command users run)
  ├── src/
  │   ├── lexer.js             ← Step 1: .alz text → tokens
  │   ├── parser.js            ← Step 2: tokens → AST
  │   ├── codegen-js.js        ← Step 3: AST → JavaScript
  │   ├── repl.js              ← Interactive shell (alz with no args)
  │   └── errors.js            ← Plain English error messages
  ├── stdlib/
  │   └── _alzdb.js            ← Built-in database runtime (JSON files)
  ├── examples/
  │   ├── hello.alz            ← Simplest ALZ program
  │   ├── full.alz             ← All features demonstrated
  │   └── reportcard.alz      ← Real demo: vars, functions, math, objects
  ├── tests/
  │   └── run.js               ← Full test suite
  ├── package.json             ← name: alz-lang, bin: { alz: ./bin/alz }
  ├── README.md                ← User-facing docs
  └── INSTRUCTIONS.txt         ← This file

───────────────────────────────────────────────────────────────────────────────
  SECTION 4 — THE PIPELINE
───────────────────────────────────────────────────────────────────────────────

  When the user runs:  alz myfile.alz

  Step 1 — LEXER (src/lexer.js)
  ──────────────────────────────
    Input:  raw .alz source string
    Output: array of token objects { type, value, line }

    Token types:
      KEYWORD         reserved words (print, if, else, define, etc.)
      IDENT           user-defined names (name, age, greet)
      STRING          "hello" — no interpolation markers
      TEMPLATE_STRING "Hello {name}" — contains {varname}
      NUMBER          42, 3.14
      OP              = == != > < >= <= + - * / %
      COLON           :
      COMMA           ,
      DOT             .
      LPAREN RPAREN   ( )
      LBRACKET RBRACKET [ ]
      LBRACE RBRACE   { }
      INDENT          line is more indented than previous
      DEDENT          line is less indented than previous
      NEWLINE         end of a line
      EOF             end of file

    JS Reserved Word Protection:
      Any IDENT that matches a JS reserved word gets renamed _alz_WORD.
      Example: user writes "class = 5" → token IDENT "_alz_class"
      This prevents compiled JS from crashing on reserved names.

    Multi-word keywords (emitted as single tokens):
      "else if"        → KEYWORD 'else if'
      "repeat forever" → KEYWORD 'repeat forever'
      "repeat until"   → KEYWORD 'repeat until'
      "file exists"    → KEYWORD 'file exists'
      "add to"         → KEYWORD 'add to'  (file append)
      "serve on"       → KEYWORD 'serve on'

    Template strings:
      Any string containing { is emitted as TEMPLATE_STRING.
      Exception: \{ is an escaped brace — stays as STRING with literal {
      In codegen: TEMPLATE_STRING → JS template literal `Hello ${name}`

    "show" alias:
      If the lexer sees the word "show" it emits KEYWORD 'print' instead.
      The rest of the compiler only ever sees 'print'.

  Step 2 — PARSER (src/parser.js)
  ────────────────────────────────
    Input:  token array
    Output: AST — nested JS object tree

    Root: { type: 'Program', body: [...] }

    Statement nodes:
      Print          print expr
      Assign         name = value
      MemberAssign   obj.prop = value
      If             if / else if / else
      Each           each item in list:
      Repeat         repeat N [as counter]:
      RepeatForever  repeat forever:
      RepeatUntil    repeat until condition:
      Define         define name(params):
      Return         return value
      Call           funcName(args) as statement
      MethodCall     obj.method(args) as statement
      TryCatch       try / catch err:
      Use            use moduleName
      Stop           stop (break)
      Skip           skip (continue)
      FileWrite      write "file" content
      FileAppend     add to "file" content
      FileDelete     delete "file"
      Serve          serve on PORT:
      Route          route "/path" [method="POST"]:
      Respond        respond value
      AskStmt        standalone ask "prompt"
      ExprStmt       standalone expression

    Expression nodes:
      String          "hello"
      TemplateString  "Hello {name}"
      Number          42
      Bool            true / false
      Null            null
      Ident           variable reference
      List            [1, 2, 3]
      ObjectLiteral   { name: "Sara", age: 25 }
      BinaryOp        left OP right
      LogicalOp       left and/or right
      Not             not expr
      CallExpr        funcName(args) in expression
      MethodCallExpr  obj.method(args) in expression
      MemberAccess    obj.property
      Index           obj[index]
      Ask             ask "prompt" in expression
      FileRead        read "file"
      FileExists      file exists "file"
      HttpGet         fetch "url"
      HttpPost        post "url" with { key: val }
      RequestProp     request.field (inside route blocks)
      Request         request (whole body object)

    Operator precedence (high to low):
      unary (not, -)  →  * / %  →  + -  →  comparisons  →  and  →  or
      Enforced via layered functions:
        parseOr → parseAnd → parseComparison →
        parseAddSub → parseMulDiv → parseUnary → parsePrimary
      Never flatten into a single loop. That breaks math expressions.

    Keyword-named functions:
      parsePrimary() accepts KEYWORD tokens as callable names.
      This allows:  define add(a, b):  without the parser choking on "add".

  Step 3 — CODEGEN (src/codegen-js.js)
  ──────────────────────────────────────
    Input:  AST
    Output: JavaScript string

    Key mappings:
      print X            → console.log(X)
      print              → console.log()
      define f(a, b):    → function f(a, b) {
      each x in list:    → for (const x of list) {
      repeat N as i:     → for (let i = 0; i < N; i++) {
      repeat N:          → for (let _alz_i = 0; _alz_i < N; _alz_i++) {
      repeat forever:    → while (true) {
      repeat until cond: → while (!(cond)) {
      and                → &&
      or                 → ||
      is                 → ===
      isnt               → !==
      "Hello {name}"     → `Hello ${name}`
      { key: val }       → { key: val }
      true/false/null    → true/false/null

    Math built-ins (no import needed in ALZ):
      round(x)    → Math.round(x)
      floor(x)    → Math.floor(x)
      ceil(x)     → Math.ceil(x)
      sqrt(x)     → Math.sqrt(x)
      abs(x)      → Math.abs(x)
      max(a, b)   → Math.max(a, b)
      min(a, b)   → Math.min(a, b)
      power(a, b) → Math.pow(a, b)
      random()    → Math.random()
      log(x)      → Math.log(x)

    Variable scoping:
      ctx.declared tracks which variable names have been declared.
      First use → emits "let name = ..."
      Later uses → emits "name = ..."  (no duplicate let)

    DB stdlib (injected via _alzdb.js at top of compiled output):
      _alzSave(table, obj)
      _alzLoad(table, filter)
      _alzLoadAll(table)
      _alzRemove(table, filter)
      _alzUpdate(table, filter, newValues)
      These are called by the compiled JS when user calls db.save() etc.
      The db object is injected into the codegen header automatically.

  REPL (src/repl.js)
  ───────────────────
    Started by: alz  (no args, in a real terminal)
    Or:         alz repl

    Guards:
      If process.stdin.isTTY is false, exits with clear error message.
      This prevents the REPL from hanging when piped or in CI.

    Multi-line blocks:
      If a line ends with ":" → enters block collection mode
      Shows "    ... " prompt for each following line
      Blank line → ends block, runs it

    Ctrl+C behaviour:
      First press inside a block → cancels the block
      First press outside a block → shows exit tip
      Second press → exits

  CLI (bin/alz)
  ─────────────
    alz                   → REPL (only in real terminal, else help)
    alz <file>            → run file (auto-appends .alz if needed)
    alz run <file>        → run file (explicit, backward compat)
    alz repl              → open REPL
    alz build <file>      → compile to .js
    alz check <file>      → syntax check only
    alz version           → print version
    alz help              → print help

───────────────────────────────────────────────────────────────────────────────
  SECTION 5 — FULL ALZ SYNTAX
───────────────────────────────────────────────────────────────────────────────

  VARIABLES
    name    = "Sara"
    age     = 25
    price   = 9.99
    active  = true
    empty   = null
    items   = ["apple", "mango", "banana"]
    user    = { name: "Sara", age: 25 }

  OUTPUT
    print "Hello"
    print "Hello {name}"
    print "Name: {user.name}, Score: {score}"
    print                        // blank line

  INPUT
    answer = ask "What is your name? "

  CONDITIONS
    if age > 18:
        print "Adult"
    else if age == 18:
        print "Just 18"
    else:
        print "Minor"

    // ALZ style comparisons (preferred):
    if name is "Sara":
        print "Found her"
    if name isnt "Bob":
        print "Not Bob"

    // Also works:
    if age >= 18 and active is true:
        print "Active adult"
    if not active:
        print "Inactive"

  LOOPS
    repeat 5:
        print "Hello"

    repeat 5 as i:
        print "Step {i}"

    each item in items:
        print item

    repeat forever:
        print "running"
        stop              // exit the loop

    repeat until score > 100:
        score = score + 10

  FUNCTIONS
    define greet(name):
        print "Hello {name}"

    define add(a, b):
        return a + b

    greet("World")
    result = add(10, 5)

  LIST METHODS
    items.add("grape")
    items.remove("mango")
    items.sort()
    items.reverse()
    items.join(", ")
    items.has("apple")        // true or false
    items.length
    items.upper()
    items.lower()
    items.trim()
    items.split(" ")
    items.replace("a", "b")
    items.slice(0, 2)

  MATH BUILT-INS (no imports needed)
    x = round(3.7)
    x = floor(9.9)
    x = ceil(1.1)
    x = sqrt(16)
    x = abs(-5)
    x = max(3, 7)
    x = min(3, 7)
    x = power(2, 8)
    x = random()

  ERROR HANDLING
    try:
        data = fetch "https://api.example.com"
        print data
    catch err:
        print "Failed: {err}"

  FILES
    content = read "notes.txt"
    write "notes.txt" "Hello World"
    add to "notes.txt" "New line"
    delete "notes.txt"
    exists = file exists "notes.txt"

  HTTP REQUESTS
    data = fetch "https://api.example.com/users"
    print data

  WEB SERVER
    serve on 3000:
        route "/":
            respond "Hello World"

        route "/greet" method="POST":
            name = request.name
            respond "Hello {name}"

  DATABASE
    db.save("users", { name: "Sara", age: 25 })
    all  = db.all("users")
    one  = db.find("users", { name: "Sara" })
    db.update("users", { name: "Sara" }, { age: 26 })
    db.remove("users", { name: "Sara" })

  MODULES
    use mymodule        // loads mymodule.js from same folder

  FLOW CONTROL
    stop               // break out of loop
    skip               // continue to next iteration
    return             // return from function
    return value       // return a value

  COMMENTS
    // single line
    # single line
    /* multi line */

───────────────────────────────────────────────────────────────────────────────
  SECTION 6 — KNOWN ISSUES
───────────────────────────────────────────────────────────────────────────────

  1. fetch uses curl via child_process.execSync
     Works on Linux/Mac/Termux but fragile.
     Fix in v0.7: replace with native https module + async/await.

  2. No multi-file imports yet.
     use "./helpers.alz" does not work.
     Only .js modules in the same folder work currently.
     Fix in v0.7.

  3. REPL does not support multi-line functions well.
     define f(a): works if followed by indented lines then blank line.
     Nested blocks (if inside define) need two blank lines — one per level.
     Fix in v0.8.

  4. Error messages show line numbers but do not highlight the source line.
     Fix in v0.7: show the actual ALZ line with ^ pointer underneath.

  5. db is not injected automatically yet.
     User must ensure .alzdata/ is writable.
     Future: auto-create .alzdata/ if missing.

───────────────────────────────────────────────────────────────────────────────
  SECTION 7 — ROADMAP
───────────────────────────────────────────────────────────────────────────────

  v0.1  ✅  Variables, print, if/else, repeat, each, functions, lists
  v0.2  ✅  Files, HTTP fetch
  v0.3  ✅  Web server (serve/route/respond)
  v0.4  ✅  Database stdlib (db.save/find/all/remove/update)
  v0.5  ✅  String interpolation, objects, math built-ins, repeat as counter
  v0.6  ✅  REPL, repeat until, TTY guard, clean CLI dispatch

  v0.7  — Real HTTP + Better errors
    Replace curl with native Node https module
    Wrap fetch/post in async IIFE so await works
    Error messages show the ALZ source line + ^ pointer
    "Did you mean X?" typo suggestions

  v0.8  — Multi-file imports + Project generator
    use "./helpers.alz" — compile and inject that file
    alz new myapp — scaffold a project folder
    Circular import detection

  v0.9  — REPL improvements + Watch mode
    REPL handles nested blocks properly
    alz myapp.alz --watch — auto-rerun on file save

  v1.0  — Stable release
    All examples run without errors
    Test suite 100% passing
    Beginner-friendly errors for all common mistakes
    VS Code syntax highlighting extension
    Published on npm, GitHub public

  v2.0+ — Frontend (much later)
    page/button/input/title syntax
    Only after backend is stable

───────────────────────────────────────────────────────────────────────────────
  SECTION 8 — RULES FOR ANY AI CONTINUING THIS PROJECT
───────────────────────────────────────────────────────────────────────────────

  RULE 1  Read this file before writing any code.

  RULE 2  Never change the core philosophy.
          Simple, beginner-friendly, one way to do things.

  RULE 3  Never break existing syntax.
          If a .alz file worked before, it must still work after.

  RULE 4  Always test these three files before declaring done:
            examples/hello.alz
            examples/full.alz
            examples/reportcard.alz

  RULE 5  When adding a feature, touch ALL of these:
            lexer.js       (new token or keyword if needed)
            parser.js      (new AST node)
            codegen-js.js  (new JS output)
            tests/run.js   (new test cases)
          If you only change some of them, the feature is incomplete.

  RULE 6  No new keywords for things that work as function calls.
          db.save() is better than a "save" keyword.
          When in doubt: stdlib method, not keyword.

  RULE 7  Follow the roadmap in order. No skipping.

  RULE 8  Errors must be beginner-friendly.
          Every new error needs a plain English message in errors.js.
          Never let a raw JavaScript stack trace reach the user.

  RULE 9  The file extension is .alz — never change this.

  RULE 10 The npm package is "alz-lang". The bin command is "alz".
          Never change the bin name — it breaks every existing installation.

  RULE 11 One codegen target only: JavaScript.
          Do not add Python backend unless users are actively requesting it.

  RULE 12 Ask the developer before big design decisions.
          Renaming keywords, changing pipeline, restructuring DB —
          always confirm first. They affect every existing .alz file.

  RULE 13 The REPL must guard against non-TTY environments.
          Always check process.stdin.isTTY before starting readline.
          If not a TTY, exit with a clear message instead of hanging.

───────────────────────────────────────────────────────────────────────────────
  SECTION 9 — HOW TO ADD A NEW FEATURE
───────────────────────────────────────────────────────────────────────────────

  Example: adding length(list) as a built-in function

  Step 1 — lexer.js
    No change needed. It's a function call, not a keyword.

  Step 2 — parser.js
    No change needed. CallExpr already handles any function name.

  Step 3 — codegen-js.js
    In genExpr(), case 'CallExpr':
    Add to MATH_MAP or a new BUILTIN_MAP:
      length: (args) => `(${args[0]}).length`

  Step 4 — tests/run.js
    test('length() returns list length', () => {
      const { js } = compile('x = length(items)')
      assert(js.includes('.length'))
    })

  Step 5 — node tests/run.js
    All tests must pass before shipping.

  Step 6 — Update INSTRUCTIONS.txt Section 5 and README.md

───────────────────────────────────────────────────────────────────────────────
  SECTION 10 — PUBLISHING TO NPM
───────────────────────────────────────────────────────────────────────────────

  The package is published as "alz-lang".
  The command users type is "alz" — this comes from the bin field.
  These are two different things. Do not confuse them.

  "alz" on npm is taken by someone else (empty package, published 2022).
  You cannot use it. "alz-lang" is yours.

  Users install with:
    npm install -g alz-lang

  After install they run:
    alz myfile.alz
    alz version
    alz repl

  To delete a published version (not recommended):
    npm unpublish alz-lang@0.6.0-alpha.1 --force
    Only works within 72 hours of publishing.
    After 72 hours, npm does not allow unpublishing.

  To publish a new version:
    1. Update version in package.json
    2. npm publish

  To publish with a tag (alpha, beta):
    npm publish --tag alpha

  To make a version the default (latest):
    npm dist-tags add alz-lang@0.6.0 latest

───────────────────────────────────────────────────────────────────────────────
  SECTION 11 — GIT SETUP (from Termux or any terminal)
───────────────────────────────────────────────────────────────────────────────

  First time:
    cd alz/
    git init
    git add .
    git commit -m "ALZ v0.6.0"
    git remote add origin https://github.com/alz-tech/alz.git
    git push -u origin main

  Each new version:
    git add .
    git commit -m "ALZ v0.7.0 — real HTTP, better errors"
    git push

───────────────────────────────────────────────────────────────────────────────
  END OF INSTRUCTIONS
  Last updated: ALZ v0.6.0
  Maintained by: ALZ TECH
───────────────────────────────────────────────────────────────────────────────
