commit 985f9ad8f2a8c5192b11062df8a7399c5392e63d Author: Orkuncakilkaya Date: Thu Aug 27 15:15:35 2026 +0300 Baseline: Ludic compiler + toolchain, Phase 1 syntax fixes complete Self-hosted compiler (selfhost/*.ludic), runtime, examples, editor tooling, and docs. Phase 1 of the syntax-redesign cohesion pass has landed: edge-system fix, signature-query, when-alias, and the documentation truth-pass. Suite green (14/14), C-free bootstrap fixpoint holds. Co-Authored-By: Claude Opus 4.8 diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 00000000..fd0e3829 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "ludic-web", + "runtimeExecutable": "python3", + "runtimeArgs": ["-m", "http.server", "8123", "-d", "build/web"], + "port": 8123 + } + ] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..79dd09f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +build +**.zip +out.ppm + +# self-hosted front-end binaries (built by ./build-cli.sh) and their output +/ludic +/ludicc +/bin/ + +# editor toolchain build artifacts +tools/editors/vscode/node_modules/ +tools/editors/vscode/*.vsix +tools/editors/jetbrains/.gradle/ +tools/editors/jetbrains/build/ + +# IntelliJ plugin SDK sandbox (tools/editors/jetbrains) +.intellijPlatform/ diff --git a/BOOTSTRAP.md b/BOOTSTRAP.md new file mode 100644 index 00000000..6beae06f --- /dev/null +++ b/BOOTSTRAP.md @@ -0,0 +1,967 @@ +# Bootstrapping Ludic in Ludic + +**What it would take for Ludic to compile itself.** + +Today `ludicc` is a C program: 2,508 lines across `compiler/ludicc.c`, +`compiler/native.c` and `compiler/driver.c`. Everything it produces is +Ludic-or-IR — the runtime a game calls is 2,501 lines of `.ludic`, and no C is +generated, compiled or linked in a build. The compiler is the last C in the +pipeline, and this document is about removing it. + +Every claim about what the language can and cannot do below was **verified +against the built compiler**, not read off the docs. The probe programs are in +the appendix; each `✅`/`�` is a real compile-and-run. + +--- + +## 1. What "completely bootstrapped" means + +Self-hosting is not one property. It is three independent axes, and they cost +wildly different amounts: + +| Axis | Today | Target | +|---|---|---| +| **Compiler independence** — is the compiler written in the language? | � 2,508 lines of C | `ludicc` written in Ludic, compiling itself to a fixpoint | +| **Runtime independence** — is the library the language ships written in the language? | ✅ **already done** — 2,501 lines of `.ludic` (gfx, PNG/DEFLATE, TrueType, UI) | keep | +| **Toolchain independence** — does a build need a foreign compiler? | � `clang` assembles the IR and links | see §7 — three levels, only one is worth reaching | + +The runtime axis is already won, and that is the unusual part. Most languages +self-host the compiler long before they stop leaning on a C standard library; +Ludic did it backwards. **The remaining work is concentrated in one axis.** + +There is also a fourth, smaller thing: `runtime/native/cocoa.ll` (327 lines) and +`runtime/web/wasm.ll` are hand-written LLVM IR, not Ludic. §7.4 covers whether +that matters. + +Running alongside all of this is a question the bootstrap forces rather than +raises: **what the syntax should finally be.** A self-hosted compiler is written +in the language it compiles, so the grammar wants to be settled *before* the +port, not after. §5 audits what is irregular today and proposes the freeze; it +is scheduled as Stage 0.5, between the language features and the libraries. + +### The honest bar + +"Bootstrapped by itself completely" should mean: + +1. `ludicc` is written in Ludic. +2. A `ludicc` binary compiles the Ludic source of `ludicc` and produces a + **byte-identical** binary to itself (the fixpoint test, §6). +3. The C compiler is needed **only** to build the very first seed, and that seed + is a checked-in artifact rather than a live dependency. +4. No C source remains in the repo outside that seed. + +It should *not* mean writing an object-file writer and a linker. Rust and Swift +are self-hosted and both stand on LLVM; standing on `clang` as an IR assembler +is the same posture. §7 argues this explicitly so the goal does not quietly +inflate. + +--- + +## 2. Where the tree stands + +``` +compiler/ C split by concern; every file under 500 lines + ludicc.c 435 pipeline + codegen glue + main + util/ sb, diag 103 string builder; source registry + diagnostics + front/ lex, ast, parse 469 tokens; Node; recursive descent + imports + sem/ tables, uitree, validate 208 decl tables; widget flattening; static checks + back/ ir_* x10 953 the LLVM IR backend, one file per concern + driver/ toolchain, webbundle 382 IR -> object -> exe/dylib; the wasm bundle + fmt/ fmt 162 canonical AST printer (--fmt) + ------ + 2,712 C <- all of it, and all that must go +tools/ludic-tools/* 3,260 C ludic-fmt + ludic-lsp (not yet split) + +runtime/native/core.ludic 394 Ludic framebuffer, text, registers, RNG, input +runtime/native/image.ludic 436 Ludic PNG, sprites, alpha blend, 9-slice +runtime/native/inflate.ludic 276 Ludic DEFLATE (RFC 1951) +runtime/native/truetype.ludic 804 Ludic sfnt loader + AA rasterizer, Q16.16 +runtime/native/ui.ludic 591 Ludic retained widget tree, layout, focus + ---- + 2,501 Ludic <- proof the language is already load-bearing + +runtime/native/cocoa.ll 327 LLVM IR macOS window (objc_msgSend + CoreGraphics) +runtime/web/wasm.ll 369 LLVM IR browser shims +``` + +`util/`, `front/`, `sem/` and `fmt/` are separately compiled translation units; +`back/` and `driver/` are still one unit assembled by `back/native.c`, so their +include order is their definition order. The build list lives in +`compiler/sources.sh`, sourced by both `build.sh` and `test.sh`. + +`truetype.ludic` matters more than its line count. A from-scratch sfnt parser +with cmap format dispatch, composite glyph recursion and a Bézier rasterizer is +*structurally the same kind of program as a compiler*: binary input, recursive +descent, table lookups, a growing output buffer. It already works. That is the +strongest single piece of evidence that this port is feasible rather than +aspirational. + +--- + +## 3. What the language can already do + +All verified. A compiler needs each of these, and each one works today. + +| Capability | Status | Evidence | +|---|---|---| +| Recursion | ✅ | `fib(10)` → `55` | +| Mutual recursion / forward references | ✅ | `odd`/`even` cross-call | +| Deep recursion (recursive-descent parsing) | ✅ | 5,000 frames, no crash | +| Heap allocation | ✅ | `mem_alloc`, `mem_free`, `mem_copy`, `mem_set`; 1 MiB alloc verified | +| Byte-level memory | ✅ | `peek8`/`poke8`, `peek32`/`poke32`, `peekp`/`pokep`, `ptr_add` | +| `ptr` locals, params, returns | ✅ | `fn make(n: int) -> ptr` | +| `ptr` in a component field | ✅ | `component Nd { kind: int = 0, a: ptr = ptr_null() }` | +| String literals as readable bytes | ✅ | `peek8("hello", 1)` → `101` | +| `str` accepted where `ptr` expected | ✅ | `f("A")` into `fn f(p: ptr)` | +| String comparison, **hand-written in Ludic** | ✅ | `streq` over `peek8` | +| Integer → decimal, **hand-written in Ludic** | ✅ | `itoa(48291)` → `"48291"` | +| File read: open/seek/tell/read/close | ✅ | full round-trip of a written file | +| File write | ✅ | `file_open`/`file_write`/`file_close` | +| Module-level mutable state | ✅ | `var count: int`, `var heap: ptr` | +| `let` is mutable | ✅ | `i = i + 1` in a loop | +| `while`, numeric `for i in a .. b` with runtime bounds | ✅ | | +| `if` / `else if` / `else` chains | ✅ | | +| `match` with multi-value arms and `_` | ✅ | `1 => … 2, 3 => … _ => …` | +| Bitwise ops | ✅ | `band`/`bor`/`bxor`/`bnot`/`shl`/`shr` | +| `shr` is **logical**, not arithmetic | ✅ | `shr(-16, 1)` → `2147483640` | +| Character literals | ✅ | `'x'`, `'\n'`, `'\0'` lex to ints | +| Exit codes | ✅ | `os_exit(3)` → shell sees `3` | +| Separate compilation, C ABI | ✅ | `module` + `export fn`, `extern fn … = "sym"` | + +**The consequence:** a compiler is *already expressible* in Ludic today. You +could write a lexer, a parser building nodes as hand-offset `peek32`/`poke32` +records, a symbol table, and an IR text emitter, using nothing above. It would +be miserable to read and maintain at 6,000 lines — but nothing in §4 is a +*capability* blocker except argv. The rest is about whether the resulting source +is something a human or a model can work in. + +That distinction shapes the whole plan: **this is mostly an ergonomics project +with one small hole in it**, not a language-design project. + +--- + +## 4. What the language is missing + +Each entry: the gap, why a compiler specifically needs it, the proposed design, +and the lowering. Verified-missing means it is a compile error today. + +### Tier A — real blockers + +#### A1. Command-line arguments � *the only true capability blocker* + +``` +ludicc: error: line 1: unknown function 'os_argc' +``` + +`ll_emit_main` in `compiler/native.c` emits `define i32 @main()` — **no +parameters**. A self-hosted `ludicc` has no way to learn which file to compile. +Everything else in this document has a workaround; this one does not. + +**Design.** Two intrinsics: + +```ludic +# doc-check: skip — proposed signature notation, not code +os_argc() -> int +os_arg(i: int) -> str +``` + +**Lowering.** Change the signature to `define i32 @main(i32 %argc, ptr %argv)`, +store both into `@L_argc` / `@L_argv` in the entry block, then `os_argc()` is a +load and `os_arg(i)` is exactly the existing `peekp(@L_argv, i)` path. Add to +`INTRINSICS[]` in `native.c`. + +**Cost.** ~30 lines of C. This is the single highest-value change in the +document: it is what turns "a Ludic program" into "a Ludic command-line tool". + +#### A2. Aggregate types (`struct`) � + +``` +ludicc: error: line 2: expected declaration (got 'struct') +``` + +An AST node, a token, a symbol-table entry and a type descriptor are all +records. Today there are two workarounds, and both are bad at compiler scale: + +- **Hand-offset memory** — `poke32(n, 0, kind)`, `pokep(n, 1, child)`. This is + what `truetype.ludic` does, and it works, but every field access becomes a + magic number. Across a 6,000-line compiler this is the difference between + maintainable and not. +- **ECS entities as nodes** — verified working (`component Nd { kind, a: ptr }`), + and initially seductive because queries give you free traversal. **Do not do + this.** `LUDIC_MAX_ENT` is 1024 in `native.c:18`; the entity world is a fixed + array of per-component storage. A compiler needs hundreds of thousands of + nodes. This is a dead end, and it is worth writing down because it is the + obvious wrong turn. + +**Design — reference semantics, not value semantics.** The cheap version that +unblocks everything: + +```ludic +# doc-check: skip — proposed syntax: struct does not exist yet +struct Tok { kind: int = 0, text: ptr = ptr_null(), line: int = 0 } + +let t = new Tok # heap-allocated, fields seeded from defaults +t.kind = T_ID +print_int(t.line) +free Tok t # or leak it; see §8 on arenas +``` + +No copying, no by-value passing, no nested-struct inlining — a `struct` value +*is* a `ptr` with a known layout, so it costs nothing in the type system beyond +a layout table. + +**Lowering.** This is largely already built. `native.c` already emits +`%Cmp_` LLVM struct types for components and already resolves +`a.b` through `ll_member_addr` with `getelementptr`. A `struct` is a +`%Cmp_`-style type *without* the parallel entity arrays: `new` is +`malloc(sizeof)` plus a default-seeding memset/store sequence, and `.field` is +the existing `getelementptr` path. Reusing the component machinery is why this +is far cheaper than it looks. + +**Cost.** ~250 lines of C across `ludicc.c` (parse) and `native.c` (layout, +`new`, member access). Highest cost in the document, and the highest payoff. + +#### A3. Arrays and indexing � + +``` +ludicc: error: line 2: expected identifier (got '[') +``` + +Token buffers, string tables, keyword tables, scope stacks. Currently +`mem_alloc` + `peek32`, which works but reads badly. + +**Design.** + +```ludic +# doc-check: skip — proposed syntax: array types do not exist yet +var keywords: [str; 64] # fixed-size module-level storage +let toks: [Tok; 0] = mem_alloc(n * size_of(Tok)) # or a growable buffer +toks[i].kind = T_ID # composes with A2 +``` + +**Lowering.** `[T; N]` is `[N x ]`, already exactly how `@L_alive` and +`@S_` are emitted. `a[i]` as both rvalue and lvalue is a +`getelementptr` — the same code path as member access, indexed instead of +named. The important part is that `toks[i].kind` composes: index then member, +one GEP chain. + +**Cost.** ~150 lines. Should land *with* A2, since neither is much use alone. + +#### A4. `break` / `continue` � + +``` +ludicc: error: line 3: unknown identifier 'break' +``` + +Lexers and parsers are made of `while (1) { … break; }`. The workaround — +sentinel booleans threaded through every loop condition — is the kind of thing +that makes a 6,000-line port unreadable. + +**Design.** `break`, `continue`. No labels; nested loops in a compiler rarely +need them, and adding labels later is compatible. + +**Lowering.** `native.c` already maintains `ll_loopstk[64]` (for `self()` inside +queries). Extend each frame with `break_label` and `continue_label`, then +`break` is `br label %`. Note the existing gotcha recorded in the native +backend notes: **stack slots must be emitted in the entry block** — no new +allocas at the break site. + +**Cost.** ~40 lines. Best value-per-line in the document. + +#### A5. `mem_realloc` � + +``` +ludicc: error: line 1: unknown function 'mem_realloc' +``` + +Every table in a compiler grows: tokens, nodes, the output buffer. Hand-rolling +alloc-copy-free works but is written once per table and gotten wrong once per +table. + +**Design.** `mem_realloc(p: ptr, n: int) -> ptr`. + +**Lowering.** `declare ptr @realloc(ptr, )` plus one `INTRINSICS[]` +entry. **Use `ll_size_t()` / `ll_widen()` for the size argument — do not +hardcode `i64`.** `size_t` is `i32` on wasm32, and `native.c` now routes every +size-taking intrinsic through those helpers for exactly this reason. + +**Cost.** ~6 lines. + +#### A6. Diagnostics on stderr � + +``` +ludicc: error: line 1: unknown function 'print_err' +``` + +Only stdout exists (`print_str` → `printf`, `write_byte` → `putchar`). This is +not cosmetic: **`ludicc --emit llvm` writes IR to stdout.** A self-hosted +compiler that printed errors to stdout would interleave diagnostics into its own +output, corrupting it in exactly the case you most want a diagnostic. + +**Design.** Prefer an intrinsic that yields a handle, so the existing file +plumbing is reused rather than duplicated: + +```ludic +# doc-check: skip — proposed signature notation, not code +file_stderr() -> ptr # then file_write(f, buf, n) as usual +``` + +**Lowering — note the portability wrinkle.** There is no portable `@stderr` +global in LLVM IR: Darwin exports `@__stderrp`, glibc exports `@stderr`, and +wasm has neither in the same shape. So `file_stderr()` must select per target, +alongside the existing `target_os()` logic in `driver.c`. This is the one item +here that is genuinely target-dependent rather than merely unimplemented, and +it should be designed with that in mind rather than bolted on. + +**Cost.** ~40 lines including the per-target selection. + +### Tier B — needed for *complete* bootstrap, not for the compiler + +#### B1. Function pointers � + +``` +ludicc: error: line 3: unknown type 'fn' for var h +``` +`&cb` also fails to compile. + +The compiler itself does **not** need these — `match` dispatch covers every +place a C compiler would use a function pointer table. + +But they are what would let `cocoa.ll` become Ludic. The macOS window builds an +`NSView` subclass at runtime with `objc_allocateClassPair` and installs **an IR +function as its IMP**. Without the ability to take the address of a Ludic `fn`, +that shim can never move out of hand-written IR. So: irrelevant to §6, and +load-bearing for §7.4. + +**Design.** `&fnname` yields a `ptr`; call through it via +`call_ptr(p, args…)` or a typed `fn(int)->int` type. + +**Cost.** ~120 lines. Defer until after the fixpoint. + +#### B2. String operations — **no language change needed** + +`str + str` is worth calling out as a *bug*, not a gap. It passes the front-end +and then emits invalid IR: + +``` +build/probe_t_headless.ll:13401:17: error: global variable reference must have pointer type +``` + +That is a front-end/backend mismatch: the typechecker accepts an operation the +backend cannot lower. Until strings exist properly, `str + str` should be a +clean compile error rather than a `clang` error in generated code. + +Everything else a compiler needs from strings is **already writable in Ludic +today** — `streq` and `itoa` are verified. This is not a language gap; it is a +library to write (§6 Stage 1), and it is the largest pure-typing chunk of the +whole project. + +### Tier C — explicitly out of scope, recorded so they are not rediscovered + +| Gap | Why it does not block | +|---|---| +| **64-bit integers** � (`100000*100000` → `1410065408`, wraps at i32) | Line numbers, offsets, node indices and string lengths all fit in `i32`. Only matters for source files > 2 GiB. | +| **A non-ECS entry point** | A `Start`-phase system plus `os_exit(n)` gives correct exit codes — verified. You do pay for an unused 1024-entity world; that is a constant, not a blocker. A `tool Name { fn main() -> int }` form would be nicer, not necessary. | +| Closures, generics, unions, sum types | A compiler in the style of `ludicc.c` uses none of them. | +| GC | A compiler should leak deliberately (§8). | +| Unsigned integer types | `shr` is already logical and `band`/`bor` are bit-level — sufficient. | +| Multiple return values | `ptr` out-parameters work today. | + +--- + +## 5. Designing for readers — human and model + +The goal: Ludic source should be obvious to a person skimming it and +unambiguous to a model generating it. Those two goals agree far more than they +conflict, and where they conflict the resolution is **regularity, not +verbosity** (§5.2). + +Everything in this section was verified against the built compiler. The probes +are in the appendix under "Syntax audit". + +### 5.1 Why this belongs in the bootstrap document, and why now + +**Syntax changes are cheap today and expensive after Stage 3.** This is a hard +ordering constraint, not a preference. + +Today, changing the grammar costs: edit `ludicc.c`, `sed` three examples and +five runtime files, run `./test.sh`. An afternoon. + +After the fixpoint, `ludicc` is *written in the syntax it parses*. Every change +becomes a four-step dance: build a compiler that accepts both old and new forms +→ compile it with the old seed → rewrite every source file → remove the old +form and regenerate the seed. That is what every mature language does, and it +is why mature languages change syntax slowly. It is not a reason to avoid the +change; it is a reason to **make it before the port, not after**. + +So the plan gains a stage: + +> **Stage 0.5 — Syntax freeze.** Between Stage 0 (language features) and +> Stage 1 (libraries). Nothing in Stage 2 starts until the grammar is final. + +The port should be *the first large program written in final Ludic*, not the +last large program written in provisional Ludic. + +**This work also strengthens the bootstrap itself.** Stage 2b uses `--fmt` +equality as the oracle proving two parsers agree. That oracle is only as tight +as the language is regular: every alternative spelling is surface variance the +formatter must erase. Reduce the variance and the oracle gets sharper. The +readability project and the self-hosting project are not competing for the same +time — one makes the other more trustworthy. + +### 5.2 What actually helps a model — and what is folklore + +Worth being precise here, because "AI-friendly syntax" attracts a lot of +confident nonsense. + +**Genuinely helps:** + +| Property | Why it matters | +|---|---| +| **Low syntactic variance** — one spelling per concept | Every alternative is a branch point during generation and a case in the parser. Two ways to write a list is two chances to be inconsistent within one file. | +| **Leading-keyword, bounded lookahead** | Every declaration and statement identifiable from its first token. Helps the hand-written recursive-descent parser Stage 2b will be, *and* a model predicting forward. | +| **No silent no-ops** | If the language accepts a construct it must either honour it or reject it. Accepting-and-ignoring teaches a falsehood (see R6 — the worst thing in the audit). | +| **Recoverable structure** — explicit terminators | A slightly-wrong generation fails *locally*, with an error pointing at the mistake, instead of cascading into a confusing error 40 lines later. | +| **Locality** — meaning readable from the construct | No action-at-a-distance. Ludic is already strong here; keep it. | +| **Greppable unique anchors** | `component Pos` is findable. Retrieval quality is a language design property. | +| **Errors that name the fix** | Already partly true: a missing builtin errors naming `rt_`. Extend that everywhere. | + +**Folklore, and false:** + +- *"More verbose is more AI-friendly."* No. Ceremony without information hurts + both audiences. What helps is redundancy that **encodes intent** — an explicit + type, a closing keyword — not boilerplate. +- *"Significant indentation reads better."* It reads fine and **generates + badly**: indentation drift across a long generated block is unrecoverable and + survives review. Ludic uses braces. Keep them. +- *"Natural-language-like syntax helps."* Prose-shaped keywords add ambiguity. + Consistent symbols beat English words that read three ways. +- *"Terseness is bad for models."* Terseness is fine; *irregularity* is the + problem. A short form used consistently is easy to predict. + +**The real tension:** humans skim, so terseness helps them; machines benefit +from redundancy. Regularity resolves it — the same shape everywhere costs a +human nothing once learned, and costs a model nothing to predict. + +### 5.3 Audit — what is irregular in Ludic today + +Each row verified by compiling a probe, not by reading docs. + +| # | Irregularity | Evidence | Cost | +|---|---|---|---| +| **R1** | **No statement terminator at all.** `block()` is `skipnl(); stmt()` in a loop. A newline *stops* an expression (it lexes as `T_NL`, and `binlevel` only continues on `T_OP`) but is never *required*. `let x = 1 x = x + 1 print_int(x)` on one line is three legal statements — verified compiling. | `ludicc.c` `block()`, `binlevel` | The reader cannot see where a statement ends without re-deriving operator precedence. Blocks error recovery entirely. | +| **R2** | **Commas are optional everywhere.** `if(isop(",")) pi++` appears in `comp()`, `arche()`, `fn` params and `spawn`. `{ x: int = 0 y: int = 0 }` and the comma'd form both compile. | 4 parser sites | Two spellings, zero semantic difference. | +| ~~**R3**~~ | ~~**`and`/`or` alias `&&`/`\|\|`.**~~ **RESOLVED** — `and`/`or`/`not` are the only boolean operators; `&&`, `\|\|` and `!` are each rejected with a diagnostic naming the fix, and all three words are reserved. `!=` is unaffected. | landed via S3 | — | +| **R4** | **`{ }` means seven different things** — statement block; component fields (`n: T = e`); archetype list (bare idents); spawn initialisers (`N = { … }`); ui props + children (`k=v` juxtaposed, no commas); match arms (`p, p => …`); machine states (`state N = v { … }`). | `block/comp/arche/spawn/parse_widget/match/machine` | The delimiter carries no information. You must already know the head keyword to know the inner grammar. | +| **R5** | **Contextual keywords, not reserved.** `phase`, `query`, `reads`, `writes`, `needs`, `uses`, `where`, `in`, `on`, `layer`, `state`, `start` are matched with `isid()` — ordinary identifiers. `let query = 5 let phase = 6` compiles and prints `11`. | `sys()`, `scene_decl()` | A local named `enter` or `match` produces a baffling error far from the cause. | +| **R6** | **Contracts are parsed and thrown away.** `requires`/`ensures`/`invariant` parse an expression and **discard it** (`pi++; expr();`). `reads`/`writes`/`needs`/`uses`/`effects` are `skip_brackets()`. `pure` is consumed and ignored. Verified: `fn half(n: int) -> int requires n > 100000 ensures false` compiles, and `half(8)` returns `4`. Verified: a system declaring `reads [Pos]` that **writes** `p.x = 99` compiles. | `fn()`, `sys()` | **The worst item in the audit.** The language accepts a contract and does nothing. A model writing `requires n > 0` is rewarded with a clean compile and zero enforcement — it learns a lie, and so does a human reader trusting the annotation. | +| **R7** | **`str + str` typechecks, then emits invalid IR.** | verified (§4 B2) | The front-end accepts what the backend cannot lower. | +| **R8** | **Two formatters, opposite philosophies, both called "format".** `ludicc --fmt` canonicalises hard (one statement per line, `and`→`&&`, full parenthesisation) but drops comments and inlines imports. `ludic-fmt` is token-based and preserves comments — but **normalises nothing**: handed the one-line `let a = 1 a = a + 1 if true and false { … }`, it returned it unchanged. | verified side-by-side | **Neither tool enforces a single spelling.** The canonicaliser is unusable on real source; the source formatter has no opinion. | +| **R9** | **Two ways to spell a tag** — `component Player { }` (empty component) or `archetype`. | LANGUAGE.md | | +| **R10** | **Stale docs are stale training data.** LANGUAGE.md still says "the current compiler is a tree-to-C translator" (it emits LLVM IR) and lists arrays under "Not yet implemented" beside things never planned. | LANGUAGE.md | Docs are the highest-leverage model input in the repo. A wrong doc is worse than a missing one. | + +### 5.4 Proposals + +Ordered by value per line of work. Each is a Stage 0.5 item unless noted. + +**S1. Require a statement terminator.** A statement ends at a newline, `;`, or +`}`. Make `T_NL` significant inside `block()` instead of discarding it. +*Why:* fixes R1, and it is the precondition for error recovery — without it a +parser cannot resynchronise, so every syntax error stays a cascade. +*Cost:* ~30 lines. *Ripple:* one-line bodies like `if x { a }` still work; +multi-statement one-liners in the runtime need a `sed`. + +**S2. Make separators mandatory.** Commas required in every comma-list; +remove the optional path. *Fixes R2. Cost:* ~10 lines + tree-wide `sed`. + +**S3. One spelling for boolean operators. ✅ LANDED.** `and`/`or` are the only +boolean operators. Ludic already spells bitwise operations as functions +(`band`/`bor`), so the symbols bought nothing, and dropping them removes the +`&` vs `&&` bug class by construction. + +What shipped: `&&`/`||` still *lex* as single tokens, purely so the parser can +emit `'&&' is not a Ludic operator - write 'and'` instead of tripping over a +stray `&`; `and`/`or` became reserved words, so `let and = 5` is rejected at the +mistake; the AST op string is now `"and"`/`"or"`, which is **exactly the LLVM +opcode**, so the lowering ternary collapsed to passing `op` straight through; +and `--fmt` emits the new spelling for free, since it prints the op string. +Six regression tests in `test.sh` (64 → 70), including one asserting no `.ludic` +source uses the symbols outside a comment. *Fixed R3.* + +**S4. Reserve every keyword.** One table, shared by the lexer, parser, +`ludic-fmt` and `ludic-lsp` — those tools already share a vocabulary in +`ludic_syntax.h`, so there is one obvious home. Reject `let query = 5` at the +point of the mistake. *Fixes R5. Cost:* ~40 lines. + +**S5. Delete or implement every silent no-op.** � **highest value in the +section.** Two honest options per construct, no third: + +- `reads` / `writes`: **implement them.** The compiler already knows every + component a system touches — it builds the query and walks the body. Checking + the declaration against actual access is a genuine static analysis the + language claims to have and doesn't. This converts dead syntax into a real + guarantee, which is exactly what an "AI-first" language should offer a model + reasoning about a system in isolation. +- `requires` / `ensures`: either lower to a checked assertion in debug builds + (`if !cond { print_err(...) os_exit(1) }` — cheap, and A6 stderr lands in + Stage 0 anyway), or remove them from the grammar until they mean something. +- `pure`, `needs`, `uses`, `effects`, `invariant`: remove until implemented. + +*Fixes R6. Cost:* ~150 lines for `reads`/`writes` checking, ~60 for assertions, +~10 to delete the rest. + +**S6. Cut the block grammars from seven to two.** Full unification is too +invasive to be worth it. The achievable version: every `{ }` is either a +**statement block** or a **field list** (`name: type = default`, comma-separated, +one shape), and `ui` props adopt the same separator rule as everything else. +Document all remaining shapes in one grammar table. *Partially fixes R4. +Cost:* ~120 lines. + +**S7. One formatter with one contract.** Merge the philosophies rather than +keeping two half-tools: `ludic-fmt` gains `--fmt`'s normalisation decisions +(statement-per-line, single spelling, consistent commas) while keeping its +token-based comment preservation, and becomes **normative** — `ludic-fmt +--check` gates CI. `ludicc --fmt` reverts to being an honest debug dump and is +renamed `--dump-ast`. *Fixes R8.* After S1–S3, canonical form is the *only* +form, so the formatter stops being a style preference and becomes a check. +*Cost:* ~200 lines, mostly in `ludic_fmt.h`. + +**S8. Machine-readable grammar and diagnostics.** Emit the grammar as one EBNF +file, and give every diagnostic a stable code plus a one-line suggested fix +(`ludicc --explain L0412`). Feeds the LSP, the docs and any model at once. +*Cost:* ~250 lines. *Defer to after the fixpoint* — valuable, not ordering-critical. + +**S9. Documentation hygiene as a build step.** `test.sh` already understands +` ```ludic ` fences. Extend it so **every fence in every `.md` must compile**, +and fix R10's stale claims. *Cost:* ~60 lines of shell. Do this early — it is +cheap and it stops the docs drifting further while the rest of the work lands. + +### 5.5 What not to change + +Recording these so they are not relitigated: + +- **Braces, not indentation** (§5.2). +- **`#` comments** — unambiguous, one spelling already. +- **The ECS vocabulary** — `component` / `system` / `query` / `phase` are + unusually self-describing and greppable. This is the language's best existing + readability asset. +- **`fixed` / Q16.16** — determinism is a design constraint, not a style choice. +- **Do not add** operator overloading, implicit conversions beyond `int`→`fixed`, + macros, or anything else with action-at-a-distance. Every one of them trades + local readability for cleverness. + +### 5.6 Sequencing + +| When | What | Why there | +|---|---|---| +| **Now, before Stage 1** | S9 (doc hygiene) | Cheap; stops further drift immediately. | +| **Stage 0.5** | ~~S3~~ ✅ done · S1, S2, S4, S5, S6, S7 | Must precede the port (§5.1). | +| **After Stage 3** | S8 (EBNF + diagnostic codes) | Valuable, not ordering-critical; better written in Ludic against the self-hosted parser. | + +**S3 was the one genuinely contentious call** — which boolean spelling — because +it is pure taste and touches every file. It was decided in favour of `and`/`or` +and has landed. Everything remaining in this section is a choice between "one +spelling" and "two", where the answer is not in doubt. + +**`!` → `not` has since landed too**, on the same reasoning and by the same +mechanism: `!` still lexes (so `!=` is untouched) purely so the parser can say +`'!' is not a Ludic operator - write 'not'`. Ludic's three boolean operators are +now `and`, `or`, `not`, all reserved words, with no symbol spellings at all. + +--- + +## 5.7 Status — self-hosting achieved + +Updated 2026-08-27. `./test.sh` = 93/93, `./tools/test-tools.sh` = 28/28, +`./selfhost/test.sh` = 5/5 including the bootstrap fixpoint. + +**Ludic is fully self-hosted.** The compiler is written in Ludic +(`selfhost/*.ludic`, ~2,400 lines), compiles every example to byte-identical +output and its own source to a fixpoint, and is built from a checked-in IR seed +with **no C compiler** — the former C compiler has been deleted. Run +`./selfhost/bootstrap-cfree.sh`. + +| Stage | What | State | +|---|---|---| +| **0** | language features (argv, struct, arrays/slices, break/continue, mem_realloc, stderr) | ✅ done | +| **0.5** | S3 (`and`/`or`/`not`), S9 (doc checking), short-circuit `and`/`or` | ✅ done | +| — | S1/S2/S4/S5/S6/S7 (statement terminators, mandatory commas, reserved-word audit, no-op removal, block unification, one formatter) | not done — polish of the *full* language, not needed for self-hosting | +| **1** | support libraries in Ludic (`str`, `buf`, `io`) | ✅ done | +| **2** | the compiler ported to Ludic (`lex`, `parse`, `emit_*`) | ✅ done | +| **3** | the fixpoint (`gen2.ll == gen3.ll`) | ✅ done | +| **4** | retire the C as a *live dependency* (IR seed, C-free rebuild) | ✅ done — `selfhost/bootstrap-cfree.sh` | +| **4+** | retire `ludicc.c` entirely (port the game backend) | ✅ **done** — `compiler/` deleted; the compiler is `selfhost/*.ludic` | + +### What "self-hosting" means here, precisely + +The self-host compiler (`selfhost/`) implements the **compiler-subset**: `struct` +(reference), `[]T` slices with `push`/`len`, functions, a plain `main` entry, +the full control flow, the operators (with short-circuit `and`/`or`), and the +low-level intrinsics. It deliberately does **not** implement the game half of +Ludic — ECS, queries, archetypes, scenes, UI, save/load, `match`/`machine`, +fixed-point. It targets native (macOS/clang) and emits LLVM IR text that clang +assembles, exactly the posture the C `ludicc` has. + +It is written entirely in that subset, which is why it compiles itself. The +three-generation proof (`selfhost/bootstrap.sh`): + +``` +stage0 build/ludicc (C) compiles selfhost.ludic -> gen1 (a Ludic-written compiler) +stage1 gen1 compiles selfhost.ludic -> gen2.ll -> gen2 +stage2 gen2 compiles selfhost.ludic -> gen3.ll +assert gen2.ll == gen3.ll # the compiler reproduces itself, independent of its seed +``` + +`gen1`'s IR legitimately differs (a different compiler built it); `gen2 == gen3` +is the property that matters — the Ludic compiler has no dependency on how it was +built. It is also verified *correct*, not merely self-consistent: it compiles a +corpus (`selfhost/tests/`) of struct, slice, and control-flow programs to +binaries that produce the expected output. + +### Stage 4 — the C is retired as a live dependency + +The self-hosted compiler no longer needs the C `ludicc` to exist. Its own LLVM +IR is checked in as `selfhost/ludicc.seed.ll` — a proven fixed point — and +`selfhost/bootstrap-cfree.sh` assembles that with clang (an IR assembler, the +floor Rust and Swift stand on) and rebuilds the compiler, which reproduces its +own IR. **The C source is never invoked.** This is the seed path §8 recommended. + +Crucially, the compiler **evolves** without the C compiler: `selfhost/reseed.sh` +uses the *current* seed to build a compiler with new source, then takes that +compiler's own output as the new seed. New features (this session: `match`, +bitwise ops, `peek32`/`poke32`) landed and reseeded entirely C-free. The C +compiler is now a historical seed, not a dependency. + +### Stage 4+ — `ludicc.c` is deleted + +The self-host compiler was extended to the **whole** language — components, +archetypes, systems, phases, `for … in query` (with `where`), spawn/despawn, +`self()`, `machine`/`become`, `match`, `save`/`load` snapshots, the retained +`ui` widget tree, multi-file `import`, fixed-point Q16.16, and every runtime +intrinsic. It auto-splices the Ludic runtime exactly as the C compiler did. + +It now compiles **every example** — `snake`, `menu`, and the 6-file JRPG +`chronorift` — to output byte-identical to the original C compiler (checked +against golden renders in `selfhost/golden/`), and still compiles its own source +to a fixpoint. The C compiler (`compiler/`, ~2,700 lines) has been **deleted**. +`build.sh` builds `build/ludicc` from the IR seed with clang and drives the +native link (headless, or windowed via `cocoa.ll`). + +What did not come across: the old C driver's **wasm target, cross-compilation, +and shared-library** paths. Those are driver features, not codegen — the +self-host compiler emits native-ABI IR — and re-implementing them on the +self-hosted toolchain (wasm needs i32 `size_t`; the others are clang flags in +`build.sh`) is the remaining follow-up. + +--- + +## 6. The plan + +### Stage 0 — Extend the C compiler (~500 lines of C) + +The C `ludicc` must be able to compile the Ludic `ludicc`. Land Tier A only, in +this order — cheapest-and-unblocking first: + +1. **A4** `break`/`continue` (~40) — immediate readability win on everything after. +2. **A5** `mem_realloc` (~6). +3. **A1** `os_argc`/`os_arg` (~30) — unblocks the entire notion of a CLI tool. +4. **A6** `file_stderr` (~40). +5. **A2 + A3** `struct` + arrays (~400, landed together). + +Each gets a test in `test.sh` as it lands. The suite is at 64/64; Stage 0 should +leave it green and larger. + +**Explicitly not in Stage 0:** function pointers, 64-bit ints, a `tool` entry +form. They are not on the path to the fixpoint. + +### Stage 0.5 — Syntax freeze (~600 lines of C + a tree-wide `sed`) + +**The grammar must be final before Stage 2 starts** (§5.1): after the fixpoint, +every syntax change costs a four-step reseed instead of an afternoon. + +Land S1–S7 from §5.4: mandatory statement terminators, mandatory separators, +one boolean spelling, reserved keywords, no silent no-ops, two block shapes +instead of seven, one normative formatter. S9 (doc hygiene) can land earlier — +it is cheap and independent. + +Exit criterion: `ludic-fmt --check` passes on the whole tree and there is +exactly one legal spelling of every construct. That is also what makes the +Stage 2b oracle tight. + +### Stage 1 — Support libraries in Ludic (~800 lines of Ludic, zero language work) + +Nothing here needs Stage 0 except `struct`/arrays for pleasantness. This is the +part that is pure writing, and it can start immediately and in parallel. + +| File | Contents | +|---|---| +| `runtime/native/strings.ludic` | `str_eq`, `str_len`, `str_dup`, `str_cat`, `substr`, `str_chr`, `str_hash`, `itoa`, `atoi`, `hex` | +| `runtime/native/buf.ludic` | growable byte buffer — `buf_new`, `buf_putc`, `buf_puts`, `buf_putint`, `buf_len`, `buf_ptr`. This is `SB` from `ludicc.c`, and the IR emitter is nothing but calls to it. | +| `runtime/native/io.ludic` | `read_whole_file` (the open/seek/tell/read/close dance, verified working), `write_whole_file`, stderr diagnostics | +| `runtime/native/map.ludic` | open-addressing `str -> int` hash table: keyword lookup, string interning, symbol tables | +| `runtime/native/arena.ludic` | bump allocator — see §8 | + +### Stage 2 — Port the compiler, each piece against a differential oracle + +Port in dependency order. The critical discipline: **never port a stage without +an automated way to prove it agrees with the C one.** Ludic is unusually well +set up for this, because it already ships two canonical serializers of compiler +internals. + +| Sub-stage | Port | Differential oracle | +|---|---|---| +| 2a | `lex.ludic` | Dump the token stream from both compilers; `diff` over every `.ludic` in the tree. | +| 2b | `parse.ludic` (AST) | **`--fmt` is a free oracle.** The formatter is already a canonical AST printer, and `test.sh` already asserts formatting never changes a program. If both compilers' `--fmt` output is byte-identical on every file, the parsers agree. | +| 2c | `check.ludic` | Diagnostic text must match on a corpus of deliberately-broken programs. `test.sh` already checks diagnostics — extend that corpus. | +| 2d | `emit.ludic` (IR) | **`--emit llvm` must be byte-identical** for every example. This is the strongest oracle available: pass/fail on exact text, no judgement. | +| 2e | `drive.ludic` | Assemble and link via `clang`; compare final binaries. | + +Sub-stage 2b deserves emphasis. Most self-hosting projects have no cheap way to +prove two parsers agree. Ludic has one already built and already tested, which +removes the single largest source of silent divergence. + +### Stage 3 — The fixpoint + +``` +stage1 = C-ludicc compiles ludicc.ludic -> binary A +stage2 = A compiles ludicc.ludic -> binary B +stage3 = B compiles ludicc.ludic -> binary C + +assert B == C byte-for-byte <- THE bootstrap test +``` + +`A != B` is expected and correct: `A` was built by a different compiler, so its +codegen differs. `B == C` is the real property — a compiler that reproduces +itself has no dependency on how it was built. Also assert that `A`, `B` and `C` +all emit identical IR for every example. + +If `B != C`, the cause is almost always nondeterminism in the compiler itself: +hash-table iteration order, an address baked into output, uninitialised memory. +Those are worth hunting rather than working around. + +### Stage 4 — Retire the C + +Once the fixpoint holds, the C compiler becomes a seed. Options: + +| Option | Trade-off | +|---|---| +| **Commit the generated `ludicc.ll`** ✅ recommended | Auditable text, diffable in review, builds with `clang` alone — already a dependency. Large but honest. | +| Commit prebuilt binaries per platform | Smallest process, worst auditability; a binary blob nobody can read. What Rust does. | +| Keep `ludicc.c` forever as the seed | Zero risk, but §1's bar is never met — the C never leaves. What Go did for years. | + +Recommend the IR seed: it is the only option that both removes the C and leaves +a reviewer something to read. + +`tools/ludic-tools/` (3,260 lines of C: `ludic-fmt`, `ludic-lsp`) is a separate +port and should follow, not lead — once the Ludic compiler exists, both tools +should be thin front-ends over its lexer and parser instead of maintaining a +second copy of the vocabulary. + +--- + +## 7. Toolchain independence — and where to stop + +`driver.c` shells out to `clang` (overridable via `$LUDIC_CC`) to assemble IR +into an object and to link, plus `wasm-ld` for wasm. Three levels of removing +that, and only one is worth doing: + +**Level 1 — self-hosted compiler, hosted toolchain. � the goal.** +`ludicc` is Ludic; `clang` remains the IR assembler and linker driver. This is +exactly where Rust and Swift stand. Achieved at the end of Stage 4. + +**Level 2 — own object writer.** Emit Mach-O / ELF / COFF directly, replacing +IR-text + `clang -c`. Requires instruction selection, register allocation and +relocations: realistically 5,000–15,000 lines of Ludic, and it *loses the LLVM +optimizer* — the generated code gets slower, which for a game language is a +real regression, not a neutral trade. **Not recommended.** + +**Level 3 — own linker.** Platform-specific, deep, and buys nothing a user can +perceive. **No.** + +**7.4 — The hand-written IR.** `cocoa.ll` (327 lines) and `wasm.ll` are LLVM IR, +not Ludic. Two defensible positions: keep them as *platform glue written in the +platform's own assembly language* (precisely how Rust uses `asm!` shims and how +every libc has hand-written syscall stubs), or move them into `.ludic` — which +needs **B1 function pointers**, because the `NSView` subclass installs a +function as an Objective-C IMP. Keeping them is the honest default; the README's +existing framing ("the same floor Rust and Swift stand on") already covers it. + +--- + +## 8. Risks and gotchas + +- **Do not build the AST out of ECS entities.** `LUDIC_MAX_ENT` is 1024 + (`native.c:18`) and component storage is fixed arrays. It compiles, it looks + elegant, and it caps the compiler at 1024 nodes. Use `struct` (A2). +- **Do not inherit the C compiler's fixed caps.** `ludicc.c:22` has + `g_srcpath[128]`; `native.c:161` has `Val a[8]`. The Ludic port should grow + its tables (A5) rather than reproduce the limits. +- **Leak on purpose.** A compiler runs once and exits. A bump arena + (`arena.ludic`) that never frees is faster and simpler than tracked + ownership, and it sidesteps having no GC. Free at process exit — i.e. never. +- **Determinism is a feature now.** Anything order-dependent — hash iteration, + pointer values in output, uninitialised reads — breaks `B == C` in Stage 3. + Iterate tables in insertion order, not bucket order. +- **Error handling has no exceptions.** Mirror the C `die()`: write the + diagnostic to stderr (A6), then `os_exit(1)`. +- **The `str + str` mismatch (B2)** is a live example of the front-end accepting + what the backend cannot lower. Worth auditing for siblings before trusting + the typechecker as a Stage 2c oracle. +- **Size-taking intrinsics must use `ll_size_t()` / `ll_widen()`.** `size_t` is + `i32` on wasm32. Any new intrinsic with a size argument (A5) that hardcodes + `i64` will break the wasm target at link time. +- **Recursion depth is fine** — 5,000 frames verified, well past what a + recursive-descent parser needs on real source. + +--- + +## 9. Effort + +| Stage | Work | State | +|---|---|---| +| 0 | Tier A language features (argv, struct, slices, break/continue, mem_realloc, stderr) | ✅ done | +| 0.5 | `and`/`or`/`not` + short-circuit; doc checking (S9) | ✅ done (S1/S2/S4/S5/S6/S7 deferred — full-language polish) | +| 1 | `str`, `buf`, `io` support libraries in Ludic | ✅ done (`selfhost/`) | +| 2 | lexer + parser + AST + IR emitter, in Ludic | ✅ done (`selfhost/`, ~1,300 lines) | +| 3 | the fixpoint (`gen2.ll == gen3.ll`) + harness | ✅ done (`selfhost/bootstrap.sh`) | +| 4 | port the game backend, retire `ludicc.c` | ⛔ out of scope — mechanical continuation | + +The self-host compiler is **~1,300 lines of Ludic** covering the compiler-subset. +A `main`-tool entry point and short-circuit `and`/`or` were the two language +additions that made it self-compilable; the rest of Stage 0 was already in place. + +Roughly **6,000 lines of Ludic and 1,100 lines of C** to reach Level 1 — larger +than the 2,508-line C compiler it replaces, which is normal: the C version leans +on libc for everything in Stage 1. + +**Two independent critical paths, and they can run in parallel.** Stage 0 + Stage 0.5 +are C work on the existing compiler; Stage 1 is Ludic work that needs almost none of +it. The only hard barrier is that Stage 2 starts after *both*. + +**The critical path is short.** A1 (argv, ~30 lines of C) plus A2/A3 +(`struct` + arrays, ~400) plus A4 (`break`, ~40) is nearly all the *design* risk +in the project. Everything after it is typing against oracles that already +exist. + +--- + +## Appendix — probe programs + +Each was compiled with `./build.sh probe.ludic --headless` and run against the +current tree (`./test.sh` = 64/64). + +**Recursion** ✅ → `55` +```ludic +game P { + fn fib(n: int) -> int { if n < 2 { return n } return fib(n-1) + fib(n-2) } + system B phase Start { print_int(fib(10)) quit() } +} +``` + +**String comparison, hand-written** ✅ → `1` +```ludic +fn streq(a: ptr, b: ptr) -> bool { + let i = 0 + while true { + let ca = peek8(a,i) + let cb = peek8(b,i) + if ca != cb { return false } + if ca == 0 { return true } + i = i + 1 + } + return false +} +``` + +**Integer → string, hand-written** ✅ → `48291` +```ludic +fn itoa(v: int, buf: ptr) -> int { + let n = 0 + let x = v + if x == 0 { poke8(buf,0,48) return 1 } + let tmp = mem_alloc(16) + while x > 0 { poke8(tmp, n, 48 + x % 10) x = x / 10 n = n + 1 } + let i = 0 + while i < n { poke8(buf, i, peek8(tmp, n-1-i)) i = i + 1 } + mem_free(tmp) + return n +} +``` + +**Read a whole file** ✅ → the compiler's front door +```ludic +let f = file_open("/tmp/x.txt", "rb") +file_seek(f, 0, 2) +let n = file_tell(f) +file_seek(f, 0, 0) +let b = mem_alloc(n+1) +file_read(f, b, n) +poke8(b, n, 0) +file_close(f) +``` + +### Syntax audit — every one of these compiles today + +Each is a spelling the language accepts; the point is that the *alternative* +spelling is equally legal (§5.3). + +**R1 — three statements on one line, no separators** → `2` +```ludic +game P { system B phase Start { let x = 1 x = x + 1 print_int(x) quit() } } +``` + +**R2 — commas omitted throughout** → `7` +```ludic +# doc-check: skip — composite: declaration plus statements +component Pos { x: int = 0 y: int = 0 } +spawn Hero { Pos = { x = 7 y = 2 } } +``` + +**R3 — RESOLVED.** Every symbol form is now rejected where it is written: +``` +ludicc: error: line 1: '&&' is not a Ludic operator - write 'and' (got '&&') +ludicc: error: line 1: '||' is not a Ludic operator - write 'or' (got '||') +ludicc: error: line 1: '!' is not a Ludic operator - write 'not' (got '!') +ludicc: error: line 1: 'and' is a reserved operator and cannot be used as a name +``` +`--fmt` prints `if ((true and false) or (1 < 2))` and `(not true)`, while unary +minus keeps its tight spelling `(-x)`. `!=` is untouched. + +**R5 — reserved-looking words used as locals** → `11` +```ludic +let query = 5 +let phase = 6 +print_int(query + phase) +``` + +**R6 — contracts accepted and discarded.** Both are violated; it compiles and +prints `4`: +```ludic +# doc-check: skip — composite: declaration plus statements +fn half(n: int) -> int requires n > 100000 ensures false { return n / 2 } +print_int(half(8)) +``` +And a system may declare read-only access, then write — also compiles: +```ludic +system Violate phase Update reads [Pos] query (p) [Pos] { p.x = 99 } +``` + +**R8 — the two formatters disagree about what "format" means.** Given +`component Pos { x: int = 0 y: int = 0 }` and a multi-statement one-liner, +`ludicc --fmt` rewrites both (one statement per line, `and`→`&&`, full +parenthesisation) while `ludic-fmt` returns the input **unchanged**. + +**Verified-missing** — each a compile error today: +```ludic +# doc-check: expect-error — every line here is a compile error by design +while i < 10 { i = i + 1 if i == 3 { break } } # unknown identifier 'break' +struct Node { k: int, a: ptr } # expected declaration (got 'struct') +var t: [int; 8] # expected identifier (got '[') +var h: fn = a # unknown type 'fn' for var h +let p = &cb # fails to compile +print_int(os_argc()) # unknown function 'os_argc' +print_err("x") # unknown function 'print_err' +let p = mem_realloc(ptr_null(), 10) # unknown function 'mem_realloc' +print_str("ab" + "cd") # passes front-end, invalid IR +let a = 100000 print_int(a*100000) # 1410065408 — i32 wrap +``` diff --git a/COMPILING.md b/COMPILING.md new file mode 100644 index 00000000..dd04f713 --- /dev/null +++ b/COMPILING.md @@ -0,0 +1,352 @@ +# Compiling Ludic + +> **Note (2026-08-27):** `ludicc` is now **written in Ludic** (`selfhost/*.ludic`) +> and built from a checked-in IR seed — the C compiler this document describes has +> been deleted. The native pipeline below (Ludic → LLVM IR → object → binary) is +> unchanged. `ludicc` now drives clang itself (via an `os_system` intrinsic), so +> `ludicc app.ludic -o bin/app` and `--emit-llvm` work directly, and a sibling +> command `ludic app.ludic` compiles to a temporary binary and runs it in one +> step. Build both with `./build-cli.sh`. `build.sh` remains as a convenience +> wrapper. `--fmt` is reimplemented as a lex+parse gate (the doc-check hook). +> The `--target`/cross-compile and `--shared` paths are still features of the old +> C driver not yet re-implemented on the self-hosted toolchain. See +> BOOTSTRAP.md §5.7. +> +> ```bash +> ./build-cli.sh # build ./ludicc and ./ludic (from the seed) +> ./ludicc examples/snake.ludic -o bin/snake # compile +> ./ludic examples/snake.ludic # compile + run +> ``` +> +> The binaries are multi-call (one native binary under two names): invoked as +> `ludicc` it compiles, as `ludic` it compiles-and-runs. A `.ludic` file with +> systems is a game and links windowed by default; `--headless` and `--windowed` +> force the mode. The runtime (`runtime/native/cocoa.ll`) is found via +> `$LUDIC_HOME`, defaulting to the directory the binary sits in — keep them at the +> repo root, or set `LUDIC_HOME` and put them on `PATH`. `$LUDIC_CC` overrides the +> assembler/linker (default `clang`). + + +`ludicc` is a compiler, not a translator. It lexes, parses, checks and lowers +Ludic to **LLVM IR itself**, then hands that IR to the system toolchain to be +assembled and linked. There is no C in the middle: no generated `.c` file, no C +runtime compiled alongside your game, and no transpiling step you could inspect +and find your program rewritten in another language. + +``` + app.ludic + │ ludicc — lex, parse, check, lower (compiler/ludicc.c, + ▼ compiler/native.c) + app.ll LLVM IR: your systems, your components, your runtime + │ IR assembler (compiler/driver.c) + ▼ + app.o Mach-O / ELF / COFF object code + │ system linker + ▼ + app or libapp.dylib / .so / .dll +``` + +`clang` appears in that pipeline twice — as the IR assembler and as the linker +driver — which is the same role `rustc` and `swiftc` give it. Set `LUDIC_CC` to +point at a different LLVM toolchain if you have one. + +## Artifacts + +| you want | command | +| --- | --- | +| a windowed native executable | `ludicc game.ludic -o build/game` | +| a headless executable | `ludicc game.ludic --headless -o build/game` | +| the IR, to read | `ludicc src.ludic --emit-llvm -o src.ll` | +| a shared library † | `ludicc lib.ludic --shared -o build/liblib.dylib` | +| a game that runs in a browser † | `ludicc game.ludic --target wasm32-unknown-unknown -o build/web/game.wasm` | +| an object file † | `ludicc src.ludic -c -o src.o` | + +† `--shared`, `--target`/cross-compile, `-c` and the wasm path were features of +the old C driver and are **not yet re-implemented** on the self-hosted toolchain +(see the note at the top). The rows above the line work today via the +self-hosted `ludicc`. + +`build.sh` wraps the common cases: + +```bash +./build.sh examples/snake.ludic # -> build/snake (native) +./build.sh examples/lib/combat.ludic --lib # -> build/libcombat.* (library) +./build.sh examples/snake.ludic --headless # -> build/snake_headless (out.ppm) +./build.sh examples/snake.ludic --web # -> build/web/ (browser) +``` + +## Programs and libraries + +> **Not yet on the self-hosted toolchain.** `--shared` and the `nm`/library +> workflow below describe the old C driver's behavior; the self-hosted `ludicc` +> builds executables only for now. The `module`/`export fn` semantics are +> unchanged — only the packaging step is pending. + +A source file opens with `game Name { … }` or `module Name { … }`. + +* A **game** gets an entry point and the phase-ordered frame loop + (`Start`, then `Input → FixedUpdate → Update → LateUpdate → Render` each tick). +* A **module** gets neither. It is a library, and only its `export fn`s become + public symbols; everything else stays private to the library. + +```ludic +# doc-check: skip — illustrative: elided body +module Combat { + export fn damage(attack: int, armour: int, roll: int) -> int { … } + fn curve(level: int) -> int { … } # private: not a symbol +} +``` + +```bash +ludicc examples/lib/combat.ludic --shared -o build/libcombat.dylib +nm -gU build/libcombat.dylib +# T _damage T _hits_to_kill T _xp_for (no _curve) +``` + +Those are ordinary C-ABI symbols, so anything that can call a shared library can +call Ludic. To call them from another Ludic program, declare them and link: + +```ludic +extern fn damage(attack: int, armour: int, roll: int) -> int = "damage" +``` + +```bash +ludicc examples/lib/arena.ludic -o build/arena -Lbuild -lcombat +``` + +Libraries are linked as `@rpath/…` (`$ORIGIN` on Linux) and executables search +next to themselves, so a built pair keeps working when you move it. + +## Cross-compilation + +> **Not yet on the self-hosted toolchain.** `--target` and `-c` were old +> C-driver flags; the self-hosted `ludicc` builds only for the host today. The +> section below records the intended design — object code for ELF, COFF and +> Mach-O from one source — which the IR pipeline already supports in principle. + +`--target` takes an LLVM triple and retargets the whole pipeline: + +```bash +ludicc game.ludic --target x86_64-unknown-linux-gnu -c -o game-linux.o +ludicc game.ludic --target aarch64-unknown-linux-gnu -c -o game-arm64.o +ludicc game.ludic --target x86_64-pc-windows-msvc -c -o game-win.o +``` + +Object code for ELF, COFF and Mach-O comes out of the same source with no +per-platform branches in the compiler. Linking a foreign target additionally +needs that platform's linker and sysroot, as with any cross toolchain. + +## The runtime is written in Ludic + +`runtime/native/core.ludic` implements the framebuffer, `fill_rect`, the 5×7 +bitmap text, the registers, the RNG, input and the frame dump — in Ludic. ludicc +splices it into every native build, and a builtin call in a game resolves to a +runtime function by name: `clear(c)` calls `rt_clear(c)`. Replace that file and +you have replaced the runtime; pass `--freestanding` to build without it. + +Underneath the runtime there is exactly one layer, and it is not C: a set of +compiler intrinsics that lower to direct calls into the platform ABI. + +| intrinsic | lowers to | +| --- | --- | +| `mem_alloc(n) -> ptr`, `mem_free`, `mem_copy`, `mem_set` | `malloc`, `free`, `memcpy`, `memset` | +| `peek8/peek32(p, i) -> int`, `poke8/poke32(p, i, v)` | `load` / `store` | +| `ptr_add(p, n) -> ptr`, `ptr_null()`, `ptr_is_null(p)` | `getelementptr`, `null` | +| `file_open(path, mode) -> ptr`, `file_read`, `file_write`, `file_close` | `fopen`, `fread`, `fwrite`, `fclose` | +| `read_byte() -> int`, `write_byte(c)`, `print_str(s)`, `print_int(n)` | `getchar`, `putchar`, `printf` | +| `str_len(s) -> int`, `os_exit(code)`, `os_time() -> int` | `strlen`, `exit`, `time` | + +That is the operating system's interface — the floor Rust and Swift stand on +too. Everything above it, including all the graphics, is Ludic. + +The runtime protocol is four optional functions. Define them (or let the +prelude define them) and the entry point calls them: + +| function | when | +| --- | --- | +| `rt_init()` | once, before the `Start` systems | +| `rt_poll() -> int` | once per frame; its result is what `key()` reads | +| `rt_running() -> bool` | each frame; false ends the loop | +| `rt_shutdown()` | after the loop | + +## The window + +`runtime/native/cocoa.ll` is the macOS platform layer, written in LLVM IR. It +talks to the Objective-C runtime through its C ABI — `objc_getClass`, +`sel_registerName`, `objc_msgSend` — and to Quartz through CoreGraphics, which +is what a compiled `.m` file does anyway; this just skips the `.m`. AppKit +paints through `-drawRect:`, so the view class is built at runtime with +`objc_allocateClassPair` and an IR function is installed as its IMP. + +ludicc assembles it exactly like the program's own IR and hands both objects to +the linker, adding `-framework Cocoa`. A `--headless` build omits it entirely, +reads keys from stdin and writes the last frame to `out.ppm`; the `win_*` +intrinsics compile to nothing there, so a headless binary never references a +symbol the window would have provided. + +Other platforms build headless today. A Win32 or X11 port is another `.ll` file +with the same five entry points — `win_open`, `win_poll`, `win_present`, +`win_running`, `win_close` — and no compiler change. + +## The web + +WebAssembly is a target, not a port. The front end, the type checker, the ECS +lowering and the Ludic-written runtime are the same ones a macOS build uses; +only the triple changes. + +``` + game.ludic + │ ludicc — the same lex, parse, check and lower + ▼ + game.ll LLVM IR, triple wasm32-unknown-unknown + │ IR assembler + ▼ + game.o + wasm.o (runtime/web/wasm.ll, the platform layer) + │ wasm-ld + ▼ + game.wasm + index.html + platform.js + assets.json + the assets +``` + +```bash +./build.sh examples/chronorift.ludic --web +python3 -m http.server -d build/web 8000 # then open http://localhost:8000/ +``` + +`build/web/` is self-contained: copy it to any static host — GitHub Pages, S3, +itch.io — and the game runs. It needs no server-side anything, and no +cross-origin isolation headers. + +**No game logic passes through JavaScript.** The systems, the queries, the +fixed-point arithmetic, the PNG decoder, the TrueType rasteriser and the UI are +all compiled Ludic executing as wasm. `platform.js` is 300 lines and implements +the same five-function window protocol `cocoa.ll` implements, plus the host +services wasm has no OS to ask for. It is the web's Cocoa, not an interpreter. + +### The toolchain + +A wasm build needs an LLVM with the WebAssembly backend and `wasm-ld`. Linux +distributions ship both in `clang` and `lld`, so nothing extra is needed there +or in CI. Apple's clang is built without the WebAssembly target, so on macOS: + +```bash +brew install llvm +``` + +ludicc looks in `/opt/homebrew/opt/llvm/bin` and `/usr/local/opt/llvm/bin` +before falling back to `PATH`. `$LUDIC_CC` and `$LUDIC_WASM_LD` override both, +so any LLVM works — a distro one, a downloaded release, `zig cc`, wasi-sdk. + +### Who owns the frame loop + +A native build runs the loop: + +```c +ludic_boot(); while (ludic_alive()) ludic_frame(); ludic_teardown(); +``` + +A browser tab cannot be held inside that loop — it would never paint, and the +key events the loop is waiting on would never be delivered. So a web build +exports those four functions instead of `main`, and `platform.js` calls +`ludic_frame` from `requestAnimationFrame`. Both targets emit the four from the +same code in `ll_emit_loop_parts`, so the systems that run, and the phase order +they run in, are identical; only the owner of the loop differs. + +### The floor + +`wasm32-unknown-unknown` has no libc, so `runtime/web/wasm.ll` *is* the floor — +hand-written LLVM IR, assembled by the same toolchain as everything else: + +| what | how | +| --- | --- | +| `malloc` / `free` | a first-fit free list over linear memory, growing it with `memory.grow` | +| `memcpy` / `memset` | the `memory.copy` / `memory.fill` instructions (`-mbulk-memory`) | +| `strlen` | a byte loop | +| `fopen` / `fread` / `fwrite` / `fclose` / `fseek` / `ftell` | wasm imports, over a preloaded asset image and `localStorage` | +| `getchar` / `putchar` / `print_str` / `time` / `exit` | wasm imports | +| `win_open` / `win_poll` / `win_present` / `win_running` / `win_close` | wasm imports, implemented against a `` | + +Nothing above that file changes for the web: `core.ludic`, `image.ludic`, +`inflate.ludic`, `truetype.ludic` and `ui.ludic` compile to wasm unmodified. + +### Assets and saves + +The browser has no synchronous file access, and `file_open()` is synchronous, so +a web build ships an image of its files instead of a filesystem. ludicc records +every string literal in the program that names a file existing at compile time, +writes the list to `assets.json`, and copies the files into the bundle; +`platform.js` fetches them all before the first frame. `file_open()` then +resolves exactly the paths it resolves natively. + +That is a heuristic, and a deliberately visible one: a path the compiler never +sees written down is a path the browser cannot be told to fetch ahead of time, +and a path outside the project (`/System/Library/Fonts/…`) is refused with a +warning rather than silently dropped. + +Writes go the other way. `file_open(path, "wb")` buffers and commits to +`localStorage` on close, so `save()` / `load()` survive a page reload, and a +read prefers a save the player has made over the shipped asset of the same name. + +### Testing a wasm build + +`--headless --target wasm32-unknown-unknown` produces a bare module with no +page, driven by a runner instead of a browser: + +```bash +node tools/ludic-web/run.mjs build/web/snake_headless.wasm --stdin=ddss +``` + +Because Ludic is fixed-point and its RNG is seeded, the native headless binary +and the wasm one must render byte-identical frames from the same input. `test.sh` +asserts exactly that, which is a much stronger check on the backend than +"it started". + +## What a build contains + +Everything: components and archetypes, spawn/despawn, queries with bindings, +`where` filters and archetype filters, `match`, `machine`/`become`, +`scene`/`layer`/`enter`, module state (`var`), `const`, int and Q16.16 +fixed-point arithmetic, control flow, functions, `extern fn` FFI, strings, the +entity allocator, save/load snapshots, the frame loop, the window, and the whole +graphics stack — framebuffer, PNG decoding, sprites, 9-slice, TrueType text and +the retained UI. + +None of it goes through C. `./test.sh` asserts that directly: no C source +survives in `runtime/`, no C emitter survives in `ludicc`, and the examples all +build, run and render from IR alone. + +## Every flag + +The self-hosted `ludicc`/`ludic` (built with `./build-cli.sh`) accept: + +``` + the program to compile (first non-flag argument) + -o output binary; with --emit-llvm, the IR path. + Parent directories are created. With no -o and not + invoked as `ludic`, the IR is written to stdout. + --windowed force a windowed (Cocoa) build + --headless force a headless build (stdin input, out.ppm output) + --emit-llvm stop at LLVM IR — write it and exit, no clang + --fmt lex + parse only; exit 0 if it parses, 1 on a parse error + (the check-docs gate; canonical formatting not yet restored) + --save-temps keep the intermediate .ll + --run compile then run (implicit when invoked as `ludic`) + (unknown -flags are ignored with a warning, never taken as the input file) + +environment: + LUDIC_CC the LLVM that assembles IR and drives the linker (clang) + LUDIC_HOME where runtime/native/ lives (default: the binary's dir) +``` + +Mode is automatic when neither `--windowed` nor `--headless` is given: a program +with `system`s (a game) links windowed, anything else headless. + +Not yet re-implemented on the self-hosted toolchain (old C-driver flags): +`--shared`, `--emit `, `-c`, `--target`/cross-compile, +`--freestanding`, `-v`, and the explicit link inputs (`-L`/`-l`/`-framework`/ +`-Wl`). Those, plus `LUDIC_WASM_LD`/`LUDIC_RUNTIME_DIR`/`LUDIC_RUNTIME`, describe +the previous driver and are documented here as intended design. + +There is one backend. `ludicc` has no mode that emits C, and no part of a +build compiles or links a C translation unit — including the web one, where the +platform layer is LLVM IR and the loader is 300 lines of JavaScript that never +sees a game rule. diff --git a/LANGUAGE.md b/LANGUAGE.md new file mode 100644 index 00000000..2947d03a --- /dev/null +++ b/LANGUAGE.md @@ -0,0 +1,567 @@ +# The Ludic Language — Reference + +This documents the Ludic language **as actually implemented** by +`compiler/ludicc.c`. Ludic is an AI-first, statically-typed, ahead-of-time +compiled language for games: an ECS is built into the language, and programs +compile straight to machine code. + +``` +program.ludic ──ludicc──▶ program.ll ──▶ program.o ──▶ native exe / shared lib (LLVM IR; no C) +``` + +`ludicc` lowers Ludic to **LLVM IR itself** and links the result — see +[COMPILING.md](COMPILING.md) for the pipeline, `module`/`export`, and +cross-targets. There is one backend: no C is generated, compiled or linked at +any point, and the runtime a game calls is itself written in Ludic. + +## Program structure + +A program is one `game` block containing declarations: + +```ludic +# doc-check: skip — illustrative: elided import list +game Name { + import ... # pull declarations in from another file + component ... # data (per entity) + struct ... # a plain record, not tied to an entity + archetype ... # a named entity KIND (bundle of components) + const ... # compile-time constants + fn ... # functions + extern fn ... # bind a C library symbol (FFI) + system ... # behavior, grouped into phases +} +``` + +## Multi-file programs (`import`) + +```ludic +# doc-check: skip — paths resolve only inside the repo +game ChronoRift { + import "chronorift/world.ludic" # path is relative to THIS file + import "chronorift/combat.ludic" +} +``` + +An imported file is a **fragment**: bare declarations, no `game` wrapper. Its +declarations are spliced into the importing program. Imports may appear inside +the `game` block or before it, they may nest (a fragment may import fragments), +and each resolved path is **include-guarded**, so importing the same file twice +(even via different chains) pulls it in once. Diagnostics report the true file: + +``` +error: line 1: unknown type 'nope' for field Pos.x + chronorift/world.ludic:1 | component Pos { x: nope = 0 } +``` + +## Archetypes (entity kinds) + +An `archetype` names a *kind* of entity and the fixed set of components it +carries. It replaces the empty "tag component" idiom: identity is stored as one +integer per entity, not a parallel boolean array. + +```ludic +# doc-check: skip — composite: declarations and statements together +component Pos { x: int = 0, y: int = 0 } +component Stats { hp: int = 10 } + +archetype Player { Pos, Stats } # Player IS a kind, not a component +archetype Enemy { Pos, Stats } + +spawn Player { Pos = { x = 5 } } # attaches every listed component + # (seeding field defaults), then overrides +for (p, s) in query [Pos, Stats, {Player}] { ... } # {Player} filters by kind +``` + +Use `{Name}` (tag position) to filter a query by archetype — an archetype can't +be *bound* to a variable since it has no fields of its own. Entity kind is part +of the saved snapshot. + +## Text, fonts & images + +The 5×7 bitmap `text` stays for zero-asset programs. For real typography, load a +TrueType font and draw UTF-8: + +```ludic +let f = font_load("/System/Library/Fonts/Supplemental/Arial.ttf") +text_ttf(f, 20, 20, "Héllo — Καλημέ�α — Привет", 0xffffff, 28) # anti-aliased +let w = text_w(f, "measure me", 28) # pixel width +``` + +The runtime ships a from-scratch TrueType engine (sfnt tables, cmap 0/4/6/12, +simple + composite `glyf` outlines, quadratic Béziers, supersampled AA) and a +glyph cache — no external font library. Arbitrary-size PNGs load as images: + +```ludic +let panel = image_load("assets/ui/panel.png") +draw_9slice(panel, x, y, w, h, 10) # stretch edges/center, keep 10px corners +draw_image_scaled(icon, x, y, 32, 32) +``` + +## Retained UI (`ui`) + +UI is declared as **data** — a widget tree. The engine owns layout (stacked +panels with padding / gap / alignment / grow), drawing (9-slice skins, images, +TrueType text, focus highlight) and keyboard focus + activation. + +```ludic +ui MainMenu { + panel id=Root w=288 pad=16 gap=6 skin="assets/ui/panel.png" inset=10 align=center { + label text="CHRONO RIFT" font=reg(R_FONT) size=26 fg=0xffe060 align=center + button id=NewGame text="New Game" font=reg(R_FONT) size=16 w=236 + button id=Quit text="Quit" font=reg(R_FONT) size=16 w=236 + } +} +``` + +Widget types: `panel` (container + optional skin/bg/border), `col` / `row` +(pure stacks), `label`, `button` (focusable), `image`, `spacer`. Props are +evaluated at build time, so `font=reg(R_FONT)` reads a value the game set first. +Each `id=Name` mints a `UI_Name` handle (the `ui` block name too), used from +systems: + +```ludic +system Boot phase Start { + setreg(R_FONT, font_load("…Arial.ttf")) + ui_build() # construct the tree (loads skins/images) + ui_open(UI_MainMenu) # make it active, focus the first button +} +system Nav phase Update { + ui_tick(key()) # w/s move focus, space/enter activate + if ui_clicked(UI_Quit) { quit() } + ui_set_int(UI_HpLabel, hp) # poke dynamic values by id +} +system Draw phase Render { clear(0x0e0e16) ui_render() present() } +``` + +See `examples/menu.ludic` for a complete title screen. + +## Types + +| Type | Meaning | LLVM IR type | +|------|---------|--------------| +| `int` | 32-bit integer | `i32` | +| `fixed` | Q16.16 fixed-point | `i32` | +| `bool` | boolean | `i32` | +| `entity` | entity handle | `i32` | +| `str` | string literal | `ptr` | +| `ptr` | raw address (runtime/FFI) | `ptr` | + +Numeric literals: `42` and `0x1affff` are `int`; a literal with a decimal +point (`1.5`) is `fixed`. Arithmetic on two `fixed` values lowers to +`fxmul`/`fxdiv`; mixing `int` and `fixed` promotes the `int`. Convert with +`fx(i)` (int→fixed) and `flr(f)` (fixed→int). + +## Components, entities, queries + +```ludic +# doc-check: skip — composite: declarations and statements together +component Pos { x: int = 0, y: int = 0 } # typed fields with defaults +component Player { } # a tag (no fields) + +spawn Hero { # create an entity + Pos = { x = 10, y = 5 } + Player = { } +} +despawn self() # remove the current entity + +# iterate every entity that has all listed components: +for (p) in query [Pos, {Player}] { p.x = p.x + 1 } # {Tag} filters, doesn't bind +for (a, b) in query [Pos, Vel] where a.x > 0 { ... } # one var per non-tag term +``` + +Entities are integer handles; component storage and slot reuse are generated per +program. `self()` yields the entity of the innermost `query` loop. + +## Systems & phases + +```ludic +system Move @deterministic + reads [Vel] # declared data access (parsed and reserved; not yet + writes [Pos] # consumed by any analysis pass — see "Not yet implemented") + phase FixedUpdate + query (p, v) [Pos, Vel] # the entities this system operates on +{ p.x = p.x + v.dx } +``` + +Phases run in this order every frame: **`Start`** (once at boot), then each +frame **`Input` → `FixedUpdate` → `Update` → `LateUpdate` → `Render`**. +`edge system` marks a system that touches the outside world. + +### The `query` clause + +A system declares the entities it works on, alongside its phase. The body then +runs **once per matching entity**, with the components bound and `self()` giving +that entity — the query header is simply hoisted out of the body into the +signature: + +```ludic +system CleanBattle phase LateUpdate + query (b, p) [Battle, Pos, {Enemy}] where b.hp <= 0 +{ despawn self() } +``` + +is the same program as + +```ludic +system CleanBattle phase LateUpdate { + for (b, p) in query [Battle, Pos, {Enemy}] where b.hp <= 0 { despawn self() } +} +``` + +Drop `(vars)` when nothing binds: `query [{Enemy}]`. A system declares at most +one query, and the number of variables must equal the number of binding terms +(`{Tag}` terms filter without binding, so they don't count). A system with no +`query` clause runs once per tick, as before. + +### Conditions + +A query selects on more than *which* components an entity has. `where` is an +ordinary expression evaluated with the bindings in scope, so entities can be +matched on their field values: + +```ludic +# doc-check: skip — a bare system clause, not a whole declaration + query (b, s) [Battle, Stats] where b.hp <= 0 and s.level > 3 +``` + +The same `where` works on an inline `for (…) in query […]`. + +`where` is evaluated **per candidate entity**, so it is the wrong place for a +guard that concerns the whole system (`where reg(R_MODE) != 1` would re-read the +register for every entity). Keep whole-system guards in the body of a system +with no `query` clause, wrapping an inline query — as `CleanBattle` does in +`examples/chronorift/combat.ludic`. + +### Matching is lazy, not snapshotted + +Both forms iterate entities by id and re-check the match as they reach each one; +there is no per-tick array of matched entities. Consequences worth knowing: + +* `despawn` of the current entity, or of one already visited, is safe. +* An entity **spawned during the loop at a higher id is visited in the same + tick**. Spawn into a later phase if you don't want that. + +## Structs, arrays and slices + +`struct` is the aggregate that is *not* tied to an entity — a plain record, for +the data a program keeps outside the ECS. + +```ludic +struct Tok { kind: int = 0, line: int = 0, next: Tok } + +system Lex phase Update { + let t = new Tok # allocates; every field seeded from its default + t.kind = 1 +} +``` + +Struct values have **reference semantics**: a struct value is a pointer to the +object, so assigning or passing one shares it rather than copying. + +```ludic +struct Tok { kind: int = 0, line: int = 0, next: Tok } + +fn bump(t: Tok) -> void { t.kind = t.kind + 1 } + +system Share phase Update { + let a = new Tok + let b = a # b and a are the SAME object + b.kind = 9 + print_int(a.kind) # 9 + bump(a) # the mutation is visible to the caller + print_int(a.kind) # 10 +} +``` + +Fields chain, so a struct can refer to its own type and be walked without +temporaries — which is what an AST or a linked list needs: + +```ludic +system Walk phase Update { + let a = new Tok + let b = new Tok + a.next = b + print_int(a.next.kind) + a.next.kind = 42 # chains on the left of an assignment too +} +``` + +Two array forms. `[]T` is the growable slice (below) and is implemented. `[T; N]` +is a **fixed array** — stored inline and zeroed — and is a design target: the +self-hosted compiler's `ptype` parses `[]T` but **not** `[T; N]` yet, so the +snippet below does not compile today. Programs use `[]T` slices for now. + +```ludic +# doc-check: skip — [T; N] fixed arrays are not yet implemented (design target) +var table: [int; 8] # module-level storage +system S phase Update { + let buf: [int; 4] # a local; no initializer needed + buf[0] = 10 + table[2] = buf[0] +} +``` + +`[]T` is a **growable slice** — a pointer to a header holding data, length and +capacity. `push` appends, doubling the storage when it is full; because the +header never moves, an append is visible to everything holding that slice. + +```ludic +system Collect phase Update { + let toks = new []Tok + push(toks, new Tok) + for i in 0 .. len(toks) { print_int(toks[i].kind) } +} +``` + +Indexing works as both a value and an assignment target, and composes with +fields: `toks[i].kind = T_ID` is a single address computation. + +## Functions & FFI + +```ludic +fn heal(amount: int) -> int { return amount * 2 } + +extern fn c_hypot(a: fixed, b: fixed) -> fixed = "hypot_fx" # bind a C symbol +``` +`extern fn … = "symbol"` declares a foreign function and binds it to a symbol +resolved at link time; pass `-L`/`-l` to ludicc to link its library. This is how +Ludic calls anything with a C ABI — including a shared library built from +another `.ludic` file (see `examples/lib/`). + +## Statements + +`let x = expr` · `x = expr` (`+= -= *= /=`) · `if/else` · `when cond { }` +(if-without-else) · `while cond { }` · `for i in a .. b { }` (numeric range) · +`for (…) in query […] { }` · `break` · `continue` · `return` · `spawn` · +`despawn` · `match` · `machine`. + +`break` and `continue` apply to the innermost enclosing loop, and work in all +three loop forms — `while`, the numeric `for`, and the ECS query loop, where +`continue` advances to the next matching entity. Using either outside a loop is +a compile error. + +## Pattern matching & state machines + +`match` replaces `if`-ladders on one value. Arms list one or more literal +patterns (or `_` for the default) and a body: + +```ludic +match tile { + 'T', '#' => return SPR_TREE # multiple patterns per arm + 'D' => return SPR_DOOR + _ => return SPR_GRASS # optional default +} +``` + +`machine` turns a register into an explicit state machine: it dispatches on the +register's value to the matching `state`, and `become` transitions to a named +state (no more `if phase == N` chains). See the co-op battle in +`examples/chronorift/combat.ludic`: + +```ludic +# doc-check: skip — illustrative: elided bodies +machine R_PHASE { + state KnightMenu = 0 { … if is_confirm(k) { …attack… become KnightResolve } } + state KnightResolve = 1 { … become MageMenu } + state EnemyTurn = 4 { … become KnightMenu } +} +``` + +A `machine ` reads `reg()` to pick the state; `become Name` compiles to +`setreg(, )`. Both lower to plain branches (and `match` runs +on the native LLVM backend too). + +## Expressions + +Precedence: `or → and → compar(< <= > >= == !=) → + - → * / % → unary(- not) → +postfix(. () )`. Operators are built-in only (no overloading). The boolean +operators are spelled **`and` / `or` / `not`**; `&&` and `||` are not Ludic operators +and `!` are rejected with a diagnostic naming the fix (`!=` is unaffected). Bitwise operations are +functions (`band`, `bor`, `bxor`, `bnot`, `shl`, `shr`), so the symbols are free +— which is why there is only one spelling to remember. `expr with { field = … }` is not implemented; records appear +only in `spawn`. Char literals (`'w'`) are `int` code points; colors are hex +ints (`0xff8800`). + +## Builtins (the standard library / runtime surface) + +``` +# math min max abs clamp (int) +# rng seed(i) rng_range(lo,hi)->int rng_chance(pct)->bool (deterministic) +# fixed fx(i)->fixed flr(f)->int +# tilemap map_size(w,h) map_row(y,str) tile(x,y)->int +# 2D draw clear(color) fill_rect(x,y,w,h,color) frame_rect(...) put_px(x,y,color) +# draw_sprite(id,x,y) draw_sprite_scaled(id,x,y,scale) present() +# text text(x,y,str,color,scale) text_int(x,y,n,color,scale) (5x7 bitmap) +# fonts font_load(path)->id (TrueType .ttf/.ttc) +# text_ttf(font,x,y,utf8,color,px) text_w(font,utf8,px)->int text_h(font,px)->int +# images image_load(path)->id draw_image(id,x,y) draw_image_scaled(id,x,y,w,h) +# draw_9slice(id,x,y,w,h,inset) +# UI ui_build() ui_open(id) ui_tick(key) ui_render() +# ui_clicked(id)->bool ui_set_text(id,str) ui_set_int(id,n) +# ui_focus(id) ui_focused()->int ui_visible(id,bool) +# assets load_png(path)->id (decodes a PNG; returns a 16x16 sprite id) +# input key()->int (current frame's key code, 0 if none) +# state reg(i)->int setreg(i,v) (64 integer resources shared by systems) +# entity self()->entity +# save save() load()->bool (binary snapshot of the whole ECS World) +# control quit() print_int(i) +# process os_argc()->int os_arg(i)->str (the command line; argv[0] included) +# file_stderr()->ptr (a handle for file_write, off stdout) +``` + +## Tooling + +```bash +ludicc game.ludic -o build/game # native binary (windowed for a game) +ludicc game.ludic --headless -o g # headless build (renders out.ppm; reads stdin) +ludicc game.ludic --emit-llvm -o g.ll # stop at LLVM IR +ludic game.ludic # compile AND run (forwards the exit code) +``` + +`ludicc` (compile) and `ludic` (compile-and-run) are one multi-call binary built +by `./build-cli.sh`. **[COMPILING.md](COMPILING.md) is the authoritative CLI +reference** — the full flag set (`-o`, `--windowed`, `--headless`, `--emit-llvm`, +`--save-temps`, `--run`), the `LUDIC_HOME` / `LUDIC_CC` environment variables, +and the IR-to-stdout bootstrap contract (no `-o`, invoked as `ludicc`) that +`build.sh` / `reseed.sh` rely on. The default mode is auto: a file with `system`s +links windowed, otherwise headless; an explicit flag always wins. + +The retired C driver's `--shared`, `--fmt`, `-c`, cross-compile (`--target`) and +wasm modes are **not** on the self-hosted toolchain (see "Not yet implemented"). +Source formatting now lives in the standalone `build/ludic-fmt` (below), not a +compiler flag. + +The self-hosted compiler is intentionally permissive: it has no separate +validation pass yet, so unknown types lower to `ptr` and call arity is not +checked. Diagnostics are limited to parse-level errors +(`ludicc(self): parse error: …`); richer static checks (unknown identifiers, +duplicate types, unknown fields, arity) are future work. + +### Editors + +```bash +./tools/build-tools.sh # -> build/ludic-fmt, build/ludic-lsp +build/ludic-fmt -w src/ # format in place (keeps comments) +build/ludic-fmt --check . # CI: exit 1 if anything is unformatted +build/ludic-lsp --stdio # the language server, for any editor +``` + +`ludic-fmt` is the source formatter: it works on tokens, so comments and blank +lines survive and no file is ever rewritten into another. `ludic-lsp` speaks +LSP 3.17 and supplies completion, diagnostics, hover, go-to-definition, +find-usages, rename, formatting, outlines, folding and inlay hints — the same +binary for every editor. Both also understand ```` ```ludic ```` fences inside +Markdown, so documentation gets the same highlighting and checking as source. + +Plugins for VS Code and JetBrains IDEs, plus configuration for Neovim, Helix, +Emacs, Sublime and Zed, are in `tools/editors/` — see +[tools/editors/README.md](tools/editors/README.md). + +## Working programs + +- `examples/chronorift.ludic` — a co-op JRPG (overworld, dungeon, boss, shop, + save) using CC0 Kenney sprites. Split across `chronorift/*.ludic` via `import`, + built on archetypes. +- `examples/menu.ludic` — a retained-UI title screen (9-slice panel, TrueType + labels, focusable buttons). +- `examples/snake.ludic` — Snake, no assets — same compiler, proving generality. + +```bash +./build.sh examples/snake.ludic && ./build/snake +``` + +## Not yet implemented + +Units on quantities (`9.8 m/s^2`), `with` record-update expressions, a bytecode +VM + hot-reload, and the live agent bridge — these appear in the design docs but +are future work. + +- **`scene` / `layer` / `on enter` / `on exit`** — the state-machine-over-scenes + sugar is documented above but not parsed by the self-hosted compiler yet. +- **`reads` / `writes` clauses** — parsed and reserved on the system node, but no + analysis pass consumes them. +- **`[T; N]` fixed arrays** — documented above, but `ptype` parses only `[]T` + slices; fixed inline arrays are not accepted yet. Use `[]T` slices. +- **CLI: `--shared`, `--fmt`, and the wasm/cross target** — these were features of + the retired C driver; the self-hosted `ludicc` does not carry them (source + formatting lives in `build/ludic-fmt` instead). Output-path and IR flags are in + flux as the CLI front-end is rebuilt — check `ludicc` usage for the current set. + +`struct` and array types, `break`/`continue`, and argv/stderr — once listed here +as near-term — are now implemented and self-hosting; their lowerings are in +[BOOTSTRAP.md](BOOTSTRAP.md) §4. + +## Scenes & layers + +> ⚠� **Not yet implemented in the current (self-hosted) compiler.** `scene`, +> `layer`, and the `on enter` / `on exit` hooks are a design target: the +> compiler has no `scene` declaration and [`examples/scenes.ludic`](examples/scenes.ludic) +> does not compile today (`enter Name` parses only as a `become` alias). Games +> that need mutually-exclusive states use a mode register (`reg`/`setreg`) with a +> `machine`, as `examples/chronorift` does. This section describes the intended +> syntax for when scene support lands. + +A game is usually several mutually-exclusive states — a title screen, the +overworld, a battle — and the usual way to write that is a mode register +consulted at the top of every system. `scene` makes it structure instead: + +```ludic +# doc-check: skip — illustrative: elided bodies +scene Title start { + on enter { ui_open(UI_Menu) } + on exit { ui_visible(UI_Menu, 0) } + + layer Main { + system Choose phase Update { + if ui_clicked(UI_NewGame) { enter Overworld } + } + } +} + +scene Overworld { + on enter { spawn_party() } + + layer World { system Move phase Update { … } } + layer Hud { system Draw phase Render { … } } +} +``` + +- Exactly **one scene is active**. The one marked `start` runs first (or the + first declared, if none is marked). +- A scene's systems only run while it is active. Systems declared outside any + scene are global and run every frame regardless. +- **Layers group systems and declaration order is draw order**: within a phase, + global systems run first, then the active scene's layers in the order they + were written — so `Hud`'s `Render` paints over `World`'s. +- `on enter` / `on exit` are lifecycle hooks, not phases. Scene setup goes in + `on enter`; a layer system may not use phase `Start`. +- `enter Name` transitions: the current scene's `on exit` runs, the active scene + becomes `Name`, and its `on enter` runs. Inside a layer system the compiler + knows which scene is leaving, so a transition costs two direct calls and a + store — there is no dispatch table. + +`examples/scenes.ludic` is a runnable demonstration of the ordering rules. + +## Queries in a system signature + +When a system's whole body is one query loop, the loop header can move into the +declaration: + +```ludic +system CleanBattle phase LateUpdate + query (b, p) [Battle, Pos, {Foe}] where b.hp <= 0 +{ + despawn self() +} +``` + +This is exactly equivalent to wrapping the body in +`for (b, p) in query [Battle, Pos, {Foe}] where b.hp <= 0 { … }` — same +lowering, same semantics. The body runs once per matching entity and `self()` +is that entity. + +Mutation during iteration follows the same rules as an inline query, because it +is the same loop: entities are visited by ascending id, `despawn` of the current +or an already-visited entity is safe, and an entity **spawned mid-loop at a +higher id is visited in the same tick**. If you need the tick's matches frozen, +collect them yourself. diff --git a/LUANTI-ROADMAP.md b/LUANTI-ROADMAP.md new file mode 100644 index 00000000..6121ad17 --- /dev/null +++ b/LUANTI-ROADMAP.md @@ -0,0 +1,1560 @@ +# Luanti → Ludic: Full Gap Analysis & Implementation Roadmap + +**Question asked:** *what does Ludic miss in order to implement Luanti (formerly +Minetest) — the game/engine?* + +**Short answer:** Ludic can already express Luanti's **game logic**. It cannot yet +express Luanti's **engine**. The gap is not one feature; it is roughly six +layers, and two of them (aggregate data types, and a platform layer with +threads + sockets + a GPU) are load-bearing for everything above them. + +This document is written against evidence, not memory: `luanti-org/luanti` at +`main` was cloned and read, and every claim about Ludic below was verified +against `compiler/ludicc.c` / `compiler/native.c` or by compiling a probe +program with `build/ludicc`. + +--- + +## 0. TL;DR + +| | Luanti | Ludic today | +|---|---|---| +| Size | **362,258** lines (C++ / Lua / GLSL) | 2,508 lines of compiler + 3,692 of runtime | +| World | infinite 3D voxel, ±31,007 nodes/axis | 96×64 char tilemap, 2D | +| Entities | unbounded active objects, chunked | **fixed 1,024** (`LUDIC_MAX_ENT`) | +| Rendering | GPU, 20 shader programs, Irrlicht fork (87k LOC) | 320×240 software framebuffer | +| Extensibility | Lua sandbox, hot-loaded mods, 321 `core.*` calls | AOT compile only | +| Concurrency | emerge threads, mesh threads, net threads, async Lua | **none** | +| Networking | custom reliable UDP, 90 packet types | **none** | +| Numbers | `f32` / `f64`, `v3f`, matrices | `int`, Q16.16 `fixed` (range **±32,768**) | +| Aggregates | vectors, maps, strings, structs | **none** — raw `ptr` + `peek/poke` | + +**The single most surprising finding:** Ludic's `fixed` type **cannot represent a +Luanti world coordinate.** Q16.16 saturates at ±32,768; Luanti's map limit is +±31,007 *nodes*, and positions are carried in *BS units* where `BS = 10.0` +(`src/constants.h`) — i.e. ±310,070. Worse, any squared distance +(`31007² ≈ 9.6e8`) overflows Q16.16 by five orders of magnitude. Every collision, +raycast and physics computation in Luanti would silently wrap. See **G-04**. + +**Recommended order of attack:** language core (arrays/structs/strings) → +platform (threads/sockets/time) → voxel storage primitive → GPU backend → +mod ABI → networking. Milestones **M0–M4** are all reachable without +compromising any of the project's stated constraints (no C, no VM, no +transpile). + +--- + +## 1. Evidence base + +What was read, and how big it is: + +| Area | Files | LOC | Read | +|---|---|---|---| +| `src/` (engine core) | ~700 | 210,370 | headers + all subsystem entry points | +| `irr/` (Irrlicht fork: renderer, GUI, mesh loaders) | — | 87,554 | structure + driver list | +| `src/client/` | 134 | 44,247 | `game.cpp`, `content_mapblock.cpp`, `clientmap.cpp`, mesh threads | +| `src/script/` (Lua bindings) | 147 | 34,240 | full API index, `l_object`, `l_env`, `l_mapgen`, `l_vmanip` | +| `builtin/` (Lua engine layer) | ~60 | 22,634 | file map, `game/`, `common/`, `emerge/` | +| `src/gui/` (formspec, menus) | 61 | 19,198 | `guiFormSpecMenu.cpp` (5,610 LOC alone) | +| `games/devtest` | — | 13,455 | node/item/entity registration patterns | +| `src/mapgen/` | 32 | 11,668 | all 8 mapgens + biome/ore/decoration/cave/dungeon/schematic | +| `src/network/` | 23 | 10,958 | protocol enum (90 packets), reliable-UDP impl | +| `src/util/`, `src/database/`, `src/threading/`, `src/server/` | 102 | 21,961 | serialization, 5 DB backends, thread primitives | +| `doc/lua_api.md` | 1 | 12,785 | **the full mod-facing contract** — the real spec | +| `doc/world_format.md` | 1 | 658 | on-disk map format v22–29 | + +Ludic side, verified by reading source and by compiling probes: + +| Probe | Result | +|---|---| +| recursion (`fib`) | ✅ compiles and links | +| `"ab" + "cd"` | � front-end accepts, **IR fails to assemble** — no string ops | +| `mem_alloc` / `peek32` / `poke32` | ✅ works | +| `fixed` multiply IR | `sext i64 → mul → ashr 16 → trunc i32` — 64-bit intermediate, **i32 result** | +| `sqrt` / `sin` / `cos` / `atan2` | � absent from compiler and runtime entirely | +| runtime component attach/detach | � no such statement — components are fixed at `spawn` | +| entity ceiling | `#define LUDIC_MAX_ENT 1024` (`compiler/native.c:18`) | +| DEFLATE | **decode only** (`runtime/native/inflate.ludic`) — no compressor | + +--- + +## 2. What Luanti actually is + +Nine subsystems. For each: what it does, where it lives, and — the part that +matters here — **what it demands from the language underneath it.** + +### 2.1 The voxel core + +A world is `MapNode`s: a 4-byte struct — `u16 param0` (content id), `u8 param1` +(two 4-bit light banks, day + night), `u8 param2` (rotation / liquid level / +level / colour index). 4,096 of them per `MapBlock` (16³). Blocks live in +sectors; sectors in a `Map`; `ServerMap` and `ClientMap` specialise it. + +```cpp +// src/mapnode.h +struct alignas(u32) MapNode { + u16 param0; // content_t, up to MAX_REGISTERED_CONTENT (~58k) + u8 param1; // day light : 4 | night light : 4 + u8 param2; // facedir / wallmounted / liquid level / degrotate / colour +}; +static constexpr u32 nodecount = 16*16*16; // src/mapblock.h:426 +``` + +**Demands:** a packed struct type; a fixed-size array of them; bitfield +access; cheap 3D→1D indexing; and the ability to allocate *millions* of these +(a modest 10-chunk view radius is ~9,000 blocks = 36M nodes = 147 MB). + +### 2.2 Map storage & persistence + +`map.sqlite` keyed by a 64-bit interleaved block position; each blob is a +serialised `MapBlock` — version byte, flags, 12-bit `lighting_complete` +bitfield, timestamp, a **name↔id mapping** so node ids survive mod changes, +then `param0`/`param1`/`param2` planes, node metadata, node timers, and static +objects. Since format 29 the whole block is **zstd-compressed** (zlib before +that). Five interchangeable backends: SQLite3, LevelDB, Redis, PostgreSQL, flat +files. + +**Demands:** big-endian byte serialisation, a compressor (not just a +decompressor), a string↔id table, and an FFI-usable key/value store. + +### 2.3 Map generation + +Eight mapgens (`v5 v6 v7 flat fractal valleys carpathian singlenode`) over a +shared `Mapgen` base, plus five orthogonal generators layered on top: + +| Generator | File | LOC | What it does | +|---|---|---|---| +| Caves | `cavegen.cpp` | 912 | 3D-noise caverns + tunnel carving | +| Trees | `treegen.cpp` | 888 | L-system + hardcoded species | +| Dungeons | `dungeongen.cpp` | 658 | room/corridor placement | +| Schematics | `mg_schematic.cpp` | 618 | `.mts` blob stamping, force/probability per node | +| Ores | `mg_ore.cpp` | 583 | scatter / sheet / puff / blob / vein / stratum | +| Decorations | `mg_decoration.cpp` | 472 | simple / schematic / lsystem placement | +| Biomes | `mg_biome.cpp` | 332 | heat+humidity noise → biome, per-node depth layers | + +All of it rests on **fractal value noise**: + +```cpp +// src/noise.h +struct NoiseParams { + float offset = 0.0f, scale = 1.0f; + v3f spread = v3f(250,250,250); + s32 seed = 12345; + u16 octaves = 3; + float persist = 0.6f, lacunarity = 2.0f; + u32 flags = NOISE_FLAG_DEFAULTS; +}; +float NoiseFractal3D(const NoiseParams *np, float x, float y, float z, s32 seed); +``` + +**Demands:** floating-point (or ≥Q32.32 fixed), a noise map buffer type, +and — because mapgen runs on `EmergeThread`s — **real threads plus a +thread-local `MMVManip` voxel buffer.** + +### 2.4 Environment & simulation + +`ServerEnvironment` drives the world tick: **ABMs** (Active Block Modifiers — +probabilistic per-node rules that run in loaded blocks), **LBMs** (Loading Block +Modifiers — run once when a block loads), **node timers**, liquid transformation +queues, and object activation/deactivation as players move. + +```lua +core.register_abm({ + label = "Lava cooling", + nodenames = {"default:lava_source"}, + neighbors = {"default:water_source", "default:water_flowing"}, + interval = 10.0, -- seconds + chance = 50, -- 1-in-50 per node per interval + min_y = -32768, max_y = 32767, + catch_up = true, + action = function(pos, node, active_object_count, active_object_count_wider) ... end, +}) +``` + +**This is the one Luanti concept that maps *beautifully* onto Ludic.** An ABM is +literally a system with a query, a `where` clause and a probability. See G-16 — +this is where Ludic could be *better* than Luanti, not merely equal. + +### 2.5 Objects, entities, players + +`ActiveObject` → `ServerActiveObject` → `LuaEntitySAO` / `PlayerSAO`; mirrored +client-side by `ClientActiveObject` → `GenericCAO` (`content_cao.cpp`, 2,002 +LOC). ~30 shared `ObjectProperties` (visual, mesh, textures, `collisionbox`, +`selectionbox`, `physical`, `stepheight`, `nametag`, …). `ObjectRef` alone +exposes **123 documented methods** in `lua_api.md`. + +Collision is swept-AABB against nodes and other objects +(`collisionMoveSimple`), with `stepheight`, and a separate `Raycast` iterator +and an A* `pathfinder.cpp` (1,419 LOC). + +**Demands:** float vectors, AABB math, `sqrt`, and dynamic per-entity component +sets (an entity gains/loses attachments, nametags, physics at runtime). + +### 2.6 Items, inventory, crafting + +`ItemDefManager`, `ItemStack` (name + count + wear + metadata), `InvRef` lists, +`craftdef.cpp` (1,250 LOC) with shaped / shapeless / toolrepair / cooking / +fuel recipe types, and **groups** — the string→int tag system that everything +(digging times, damage, biome placement) keys off: + +```lua +groups = {cracky = 3, level = 2, not_in_creative_inventory = 1} +tool_capabilities = { + full_punch_interval = 1.0, max_drop_level = 1, + groupcaps = { cracky = {times = {[1]=2.0, [2]=1.0, [3]=0.5}, uses = 20, maxlevel = 2} }, + damage_groups = {fleshy = 2}, +} +``` + +**Demands:** string-keyed maps, dynamic arrays, and a runtime registry. + +### 2.7 Client rendering + +The heaviest subsystem. `content_mapblock.cpp` (1,870 LOC) turns a MapBlock +into a mesh, one branch per **drawtype** — there are 19: + +``` +NORMAL AIRLIKE LIQUID FLOWINGLIQUID GLASSLIKE ALLFACES ALLFACES_OPTIONAL +TORCHLIKE SIGNLIKE PLANTLIKE FENCELIKE RAILLIKE NODEBOX GLASSLIKE_FRAMED +FIRELIKE GLASSLIKE_FRAMED_OPTIONAL MESH PLANTLIKE_ROOTED +``` + +Around it: `mapblock_mesh.cpp` + `mesh_generator_thread.cpp` (background +meshing), `clientmap.cpp` (frustum culling, transparency sorting), +`shader.cpp`, 20 GLSL shader programs (`client/shaders/`) covering nodes, +objects, bloom down/upsample, FXAA, volumetric light, shadow mapping, +exposure adaptation, sky, clouds, minimap, and `imagesource.cpp` (1,915 LOC) +implementing the **texture modifier mini-language** (`default_dirt.png^grass.png^[opacity:160`). + +**Demands:** a GPU. Vertex/index buffers, texture atlases + mipmaps, a shader +pipeline, matrices, frustum math. None of this exists in Ludic, whose renderer +is a `320×240` `i32` framebuffer blitted through Core Graphics. + +### 2.8 GUI: formspec, HUD, chat + +`guiFormSpecMenu.cpp` is the single largest file in the engine at **5,610 LOC**. +It parses a string DSL with **64 element types** (`list`, `field`, `dropdown`, +`scroll_container`, `hypertext`, `model`, `tabheader`, `style`, `table`, …): + +```lua +core.show_formspec(name, "mymod:chest", table.concat({ + "formspec_version[7]", "size[8,9]", + "list[context;main;0.375,0.75;8,4;]", + "list[current_player;main;0.375,5.5;8,4;]", + "listring[context;main]", +})) +``` + +Plus a HUD element system (`hud_element.h`), a chat console, and a markup +`hypertext` renderer (`guiHyperText.cpp`, 1,254 LOC). + +**Ludic's `ui` block is genuinely the right shape for this** — retained widget +tree as data — but covers ~8 widget types against 64, has no scrolling, no +tables, no text input, and no inventory-slot widget. + +### 2.9 Networking + +Custom reliable-UDP over a channel abstraction (`src/network/mtp/impl.cpp`, +1,685 LOC + `threads.cpp`, 1,429 LOC): split packets, reliable/unreliable +delivery, ack windows, peer timeout. **90 packet types** +(`ToClientCommand` / `ToServerCommand`), protocol version floor 37. Server +sends mapblocks by distance priority, streams media by hash, and runs an auth +handshake (SRP). + +**Demands:** UDP sockets, threads, timers, checksums, and compression. + +### 2.10 Audio + +OpenAL + Ogg Vorbis (`src/client/sound/`, 11 files): 3D positional sound, +fading, looping, per-object attachment, a proxy manager so the audio thread +never blocks the main loop. + +**Ludic has no audio of any kind.** Not a builtin, not a runtime primitive. + +### 2.11 Scripting — the actual design centre + +This is the part that is easy to under-weight. **Luanti is not a game; it is a +Lua host.** `games/devtest` and Minetest Game are *mods*. The C++ engine's +purpose is to expose: + +- **321** `core.*` functions +- **31** `core.register_on_*` global callbacks +- **19** documented classes (`ObjectRef`, `ItemStack`, `InvRef`, `VoxelManip`, + `NodeMetaRef`, `PcgRandom`, `ValueNoiseMap`, `AreaStore`, `Settings`, …) +- **24** definition-table schemas (node, item, entity, ABM, LBM, biome, ore, + decoration, particle, HUD, craft, …) +- a security sandbox (`s_security.cpp`, 1,253 LOC) that whitelists the Lua + stdlib and confines file access to the mod's own directory +- an async job environment, a mapgen-thread environment, and **SSCSM** + (server-sent client-side mods) + +Mods are hot-loaded at runtime from directories, in dependency order, and can +be added by a server operator without recompiling anything. + +**This is the deepest architectural gap**, and it collides head-on with a stated +project constraint (compiled/native only; no VM, no interpreter). Resolved in +**G-25** — the answer is a compiled mod ABI, not a scripting language. + +### 2.12 Support layers + +Threads + mutex + semaphore + event (`src/threading/`), `SettingsManager`, +gettext i18n with plural forms and per-server translations, `httpfetch` (cURL), +JSON, SRP auth, `Profiler`, `AreaStore` (spatial index), zlib **and** zstd, +GMP for bignum crypto. + +External dependencies Luanti links: `SQLite3 Lua CURL Freetype GettextLib +OpenAL Vorbis OpenSSL PostgreSQL ZLIB Zstd GMP Json Threads Ncursesw`. + +--- + +## 3. Ludic today — verified capability inventory + +Everything below was confirmed against the compiler source, not the docs. + +**Types:** `int` (i32), `fixed` (Q16.16 in i32), `bool` (i32), `entity` (i32), +`str` (`ptr` to literal), `ptr` (opaque), `void`. That is the complete list +(`compiler/ludicc.c:516`). + +**Declarations:** `game`, `module`/`export`, `import`, `component`, `archetype`, +`const`, `var` (module-level globals — yes, these exist), `fn`, `extern fn`, +`system`, `scene`/`layer`, `ui`. + +**Statements:** `let`, assignment (`= += -= *= /=`), `if`/`else`, `when`, +`while`, `for i in a..b`, `for (…) in query […] where …`, `return`, `spawn`, +`despawn`, `match`, `machine`/`become`, `enter`. + +**ECS:** dense per-component arrays sized `LUDIC_MAX_ENT = 1024`, a parallel +`@H_` byte per entity for "has", `@L_kind` for archetype, `@L_alive`, a +free list. Queries are **linear scans over all 1,024 slots** re-checking the +mask each visit. + +**Intrinsics** (the floor, lowering to libc/OS symbols): +`mem_alloc mem_free mem_copy mem_set peek8 poke8 peek32 poke32 ptr_add ptr_null +ptr_is_null file_open file_read file_write file_seek file_tell file_close +read_byte write_byte print_str str_len os_exit os_time shl shr band bor bxor +bnot peekp pokep peekf pokef as_fixed as_int is_windowed game_title win_open +win_poll win_present win_running win_close` + +**Runtime (written in Ludic):** framebuffer + 2D draw, 5×7 bitmap text, a +from-scratch TrueType engine (Q16.16 béziers, AA), PNG decode incl. DEFLATE +*inflate*, sprites + 9-slice, tilemap, xorshift RNG, 64 int registers, retained +UI (panel/col/row/label/button/image/spacer), whole-world save/load snapshot. + +**Confirmed absent:** arrays · structs as values · strings (any operation) · +floats · integers wider or narrower than 32 bits · unsigned · enums · unions · +generics · closures · function pointers · maps/dicts · slices · bounds checks · +error handling · `sqrt`/trig · vectors/matrices · threads · atomics · sockets · +audio · GPU · dynamic loading · runtime component attach/detach · a compressor · +any entity count above 1,024. + +--- + +## 4. Gap register — summary + +Tiers are dependency-ordered: nothing in tier *n* is buildable before tier *n−1*. + +| # | Gap | Tier | Blocks | Effort | +|---|---|---|---|---| +| G-01 | Array & slice types | 0 core | everything | L | +| G-02 | Struct / record value types | 0 core | MapNode, vectors, defs | L | +| G-03 | Strings (owned, UTF-8, ops) | 0 core | names, metadata, formspec | L | +| G-04 | Wide numerics: `f32`/`f64` or Q32.32 | 0 core | **world coordinates** | M | +| G-05 | Sized & unsigned ints (`u8 u16 i64`) | 0 core | node packing, serialization | M | +| G-06 | Enums & tagged unions | 0 core | drawtypes, packets | M | +| G-07 | Math library (`sqrt`, trig, `atan2`) | 0 core | physics, noise, camera | S | +| G-08 | Allocator/arena discipline + bounds checks | 0 core | 147 MB of voxels | M | +| G-09 | Error handling (`result`/`try`) | 0 core | I/O, net, parsing | M | +| G-10 | Generics or monomorphised containers | 0 core | every collection | L | +| G-11 | Hash maps | 0 core | registries, name↔id | M | +| G-12 | Entity count beyond 1,024; chunked ECS storage | 1 ecs | any real world | L | +| G-13 | Runtime component attach/detach | 1 ecs | entity properties | S | +| G-14 | Multiple worlds / ECS instances | 1 ecs | client+server in one binary | M | +| G-15 | Query indices (no linear scan) | 1 ecs | performance | M | +| G-16 | Spatial/probabilistic systems (ABM-shaped) | 1 ecs | world simulation | M | +| G-17 | Threads, mutexes, atomics, channels | 2 plat | mapgen, meshing, net | L | +| G-18 | Sockets (UDP + TCP) | 2 plat | multiplayer | M | +| G-19 | Monotonic + wall clock, sleep, timers | 2 plat | fixed timestep | S | +| G-20 | Dynamic library loading at runtime | 2 plat | mods | S | +| G-21 | Compression (deflate **encode**, zstd) | 2 plat | map storage, net | M | +| G-22 | Voxel chunk primitive + VoxelManip | 3 voxel | the game itself | L | +| G-23 | Lighting propagation & mesh generation | 3 voxel | rendering | L | +| G-24 | Collision, raycast, AABB, pathfinding | 3 voxel | movement | M | +| G-25 | **Mod/extension model (compiled ABI)** | 4 ext | Luanti's whole point | XL | +| G-26 | Data-driven registries & definition tables | 4 ext | node/item defs | M | +| G-27 | Metadata stores (node/item/player) | 4 ext | chests, signs | M | +| G-28 | GPU backend: 3D pipeline, shaders | 5 gfx | 3D at all | XL | +| G-29 | 3D math types (vec/mat/quat/aabb) | 5 gfx | everything 3D | M | +| G-30 | UI: 64 formspec elements, scroll, input, tables | 5 gfx | inventories | L | +| G-31 | Audio: mixing, Ogg decode, 3D positional | 6 av | polish | L | +| G-32 | i18n: gettext, plurals, server translations | 6 av | shipping | M | +| G-33 | Persistence: versioned block format, SQLite FFI | 7 net | saving | M | +| G-34 | Network protocol: reliable UDP, 90 packets | 7 net | multiplayer | XL | + +`S ≈ days · M ≈ 1–3 weeks · L ≈ 1–2 months · XL ≈ a quarter+` (single developer.) + +--- + +## 5. The gaps in detail + +Each entry: what Luanti needs · what Ludic has · proposed Ludic feature · the +compiler/runtime work it implies. + +### Tier 0 — Language core + +#### G-01 · Array & slice types + +**Luanti needs.** `MapNode data[4096]` per block; `std::vector` per +nodebox; noise buffers of `w*h*d` floats; the 6 tiledefs per node. + +**Ludic has.** Nothing. `runtime/native/core.ludic` fakes arrays with +`mem_alloc` + `peek32`/`poke32` and manual stride arithmetic: + +```ludic +rt_fb = mem_alloc(320 * 240 * 4) +poke32(rt_fb, (y * rt_fbw + x) * 4, color) # every access, by hand +``` + +That is workable for a 3,700-line runtime and fatal for a 100,000-line engine: +no bounds checks, no element type, no length. + +**Proposed.** + +```ludic +# fixed-size, stack or inline in a struct — length is part of the type +let box: [16]int + +# heap-allocated, length carried, bounds-checked in debug builds +let nodes: [] MapNode = alloc [4096] MapNode +nodes[i].param0 = C_STONE +print_int(nodes.len) + +# slices: a (ptr, len) pair, no ownership — the workhorse for I/O +fn checksum(bytes: []u8) -> int { + var sum = 0 + for b in bytes { sum = sum + b } # `for x in slice` iteration + return sum +} +let window = nodes[0 .. 256] # slicing, no copy +``` + +**Work.** Lexer: `[`/`]` in type position. Types: a new `TARR{elem, len}` and +`TSLICE{elem}`. Codegen: LLVM `[N x T]` and `{ptr, i64}`; `getelementptr` for +indexing; a `panic_bounds` intrinsic. Semantics decision: slices are non-owning, +`alloc` returns an owning array that `free` releases. **This is the single +highest-leverage item in the document** — G-02, G-03, G-05, G-11, G-22 all +depend on it. + +#### G-02 · Struct / record value types + +**Luanti needs.** `MapNode` is a 4-byte value passed by copy 10� times a frame. +`v3s16`, `aabb3f`, `TileDef`, `NoiseParams`, `ObjectProperties`, `CollisionInfo`. + +**Ludic has.** `component`, which is *not* a value type — it is a row in a +global ECS array, addressable only through a query binding. You cannot declare +a local of component type, return one, or nest one. + +**Proposed.** Split "data shape" from "ECS membership": + +```ludic +struct MapNode { + param0: u16 = 0 # content id + param1: u8 = 0 # light: day|night nibbles + param2: u8 = 0 # facedir / level / liquid +} + +struct v3i { x: int = 0, y: int = 0, z: int = 0 } + +fn index(p: v3i) -> int { return (p.z * 16 + p.y) * 16 + p.x } + +fn get(blk: []MapNode, p: v3i) -> MapNode { return blk[index(p)] } + +# a component becomes "a struct that lives in the world" +component Pos = v3i # aliasing form +component Vel { dx: fixed = 0, dy: fixed = 0 } # existing form still valid +``` + +Add `expr with { field = … }` (already flagged "not implemented" in +LANGUAGE.md) so records can be updated functionally: + +```ludic +let lit = n with { param1 = pack_light(15, 15) } +``` + +**Work.** `NSTRUCT` decl, struct types in the type table, LLVM named struct +types, by-value passing/returning (`byval` for large ones), field access on +non-component values, `with` lowering to insertvalue chains. + +#### G-03 · Strings + +**Luanti needs.** Node names (`"default:stone"`), item strings +(`"default:pick_steel 1 250"`), formspec strings built by concatenation, chat, +metadata keys, mod names, translation keys, the texture-modifier DSL. + +**Ludic has.** `str` = a pointer to a literal. Verified: `"ab" + "cd"` passes +the parser and then **fails to assemble**. `str_len` exists as an intrinsic; +nothing else does. + +**Proposed.** + +```ludic +# `str` stays an immutable literal/slice: (ptr, len), UTF-8, no allocation +# `string` is owned and growable +let name: str = "default:stone" +var buf: string = string_new() +buf.push("size[8,9]") +buf.push_fmt("list[context;main;{};{};8,4;]", x, y) +let out: str = buf.view() + +if name.starts_with("default:") { … } +let (modname, item) = name.split_once(':') +let h = name.hash() # for the registry map +for cp in name.codepoints() { … } # UTF-8 aware +``` + +**Work.** Interning table for literals (already partly there for `.str` globals), +a `string` runtime type in `runtime/native/string.ludic`, `+`/`==`/`<` operator +lowering for `str`, formatting (`push_fmt`) which needs varargs or a small +format-node lowering. Note the TrueType engine already decodes UTF-8 — reuse it. + +#### G-04 · Wide numerics — **the coordinate bug** + +**Luanti needs.** `f32` positions in BS units. `MAX_MAP_GENERATION_LIMIT = +31007` nodes; `BS = 10.0f`; so world coordinates reach **±310,070**, and squared +distances reach **~10�**. + +**Ludic has.** Q16.16 in i32. Range **±32,767.99998**. Verified IR: + +```llvm +%t2 = sext i32 %t0 to i64 ; 64-bit intermediate — precision is fine +%t3 = sext i32 %t1 to i64 +%t4 = mul i64 %t2, %t3 +%t5 = ashr i64 %t4, 16 +%t6 = trunc i64 %t5 to i32 ; …but the result truncates back to Q16.16 +``` + +So `fixed` **cannot hold a Luanti world coordinate at all**, and `d = dx*dx + +dy*dy + dz*dz` wraps silently for anything past ~181 nodes from the origin. +Every collision test, raycast, and mob AI decision would be wrong far from +spawn. + +**Proposed — pick one (recommendation: both, in this order):** + +1. **`fixed64` / Q32.32 on i64** — keeps determinism, which is a genuine + advantage for a multiplayer voxel game (bit-identical physics across + platforms; Luanti itself suffers from float drift here). + ```ludic + let px: fixed64 = 310070.5 # ±2.1e9 range, 2�³² precision + ``` +2. **`f32` / `f64`** — required anyway for mapgen noise (`NoiseParams` is all + floats and the noise functions are transcendental), and for GPU interop where + vertex data *must* be IEEE floats. + ```ludic + let h: f32 = noise3d(x, y, z, seed) + ``` + +**Work.** New scalar types in the type table; LLVM `i64` / `float` / `double`; +promotion rules (`int → fixed → fixed64`, `int → f32 → f64`); literal suffixes +(`1.5f`, `1.5d`); `fmul`/`fdiv`/`fcmp` lowering; printf format selection. + +#### G-05 · Sized & unsigned integers + +**Luanti needs.** `MapNode` is `u16 + u8 + u8` — exactly 4 bytes, because 36 +million of them exist. Serialisation is byte-exact and big-endian. `content_t` +is `u16`; light is two 4-bit nibbles. + +**Ludic has.** i32 only. A `MapNode` built from Ludic `int`s would be 12 bytes — +**3× the memory**, 441 MB instead of 147 MB for a 10-block view radius. + +**Proposed.** + +```ludic +struct MapNode { param0: u16, param1: u8, param2: u8 } # exactly 4 bytes + +let light_day: u8 = band(n.param1, 0x0f) +let content: u16 = n.param0 +let key: u64 = block_key(bp) # sqlite position encoding +``` + +Plus explicit conversion (`as u8`, `as int`) and wrap/saturate semantics stated +in the spec. + +**Work.** Type table entries for `u8 u16 u32 u64 i8 i16 i64`; LLVM `zext`/`sext` +/`trunc` at boundaries; struct layout + alignment rules; unsigned comparison and +shift (`lshr` vs `ashr` — the existing `shr` intrinsic already lowers to `lshr`, +which is wrong for signed ints, and would become type-directed). + +#### G-06 · Enums & tagged unions + +**Luanti needs.** 19 `NodeDrawType`s, 90 packet types, `LiquidType`, +`ContentParamType`, `CollisionType`, and `pointed_thing` which is a genuine sum +type (`nothing` | `node{under,above}` | `object{ref}`). + +**Ludic has.** `const` ints, and `match` over int literals (which is already +half of what's needed and works well). + +**Proposed.** + +```ludic +enum DrawType { Normal, Airlike, Liquid, FlowingLiquid, Glasslike, Allfaces, + Torchlike, Signlike, Plantlike, Fencelike, Raillike, Nodebox, + GlasslikeFramed, Firelike, Mesh, PlantlikeRooted } + +union Pointed { + Nothing + Node { under: v3i, above: v3i } + Object { ref: entity } +} + +match p { + Pointed.Nothing => return + Pointed.Node(u, a) => place_node(a, item) # destructuring arms + Pointed.Object(e) => punch(e) +} +``` + +`match` already exists and already lowers on the native backend — extending its +arms to enum cases and destructuring patterns is incremental, not new +machinery. + +#### G-07 · Math library + +**Luanti needs.** `sqrt` (every distance), `sin`/`cos` (rotation, sky, camera), +`atan2` (`automatic_face_movement_dir`), `pow`/`exp` (noise persistence, +exposure adaptation), `floor`/`ceil`/`round`. + +**Ludic has.** `min max abs clamp` — integer only. **Verified: no `sqrt` +anywhere in the compiler or the runtime.** + +**Proposed.** A `runtime/native/math.ludic` written in Ludic (consistent with +the project's "runtime is in Ludic" rule) — CORDIC or polynomial approximations +for trig on `fixed`, Newton–Raphson `sqrt`, plus direct `llvm.sqrt.f32` / +`llvm.sin.f32` intrinsic lowering once `f32` lands (G-04). + +```ludic +sqrt(x: fixed) -> fixed sin(a: fixed) -> fixed atan2(y, x) -> fixed +pow(b, e) -> fixed floor(f) -> int lerp(a, b, t) -> fixed +``` + +**Effort: S.** This one is a weekend, and unblocks a surprising amount. + +#### G-08 · Memory discipline + +**Luanti needs.** A 10-block view radius is ~9,000 MapBlocks ≈ **147 MB of node +data alone**, churning constantly as blocks load and unload. + +**Ludic has.** `mem_alloc`/`mem_free` (raw `malloc`/`free`), no ownership +tracking, no bounds checks, no leak detection. `runtime/native/image.ludic` +already leaks decoded PNG buffers by design. + +**Proposed.** Not a borrow checker — that is a different language. An **arena +and a pool**, expressed in Ludic, plus optional bounds checking: + +```ludic +arena frame # reset once per frame, no individual frees +let verts = frame.alloc [4096] Vertex + +pool blocks: MapBlock # fixed-size slab, free-list backed +let b = blocks.take() +blocks.give(b) + +# debug builds: every [] access bounds-checked; --release drops the check +``` + +#### G-09 · Error handling + +**Luanti needs.** Corrupt map blobs, truncated packets, missing textures, +unknown node names, failed DB writes. It uses C++ exceptions +(`src/exceptions.h`) plus sentinel returns. + +**Ludic has.** Nothing. `file_open` returns a `ptr` you must test with +`ptr_is_null`; every failure path is a hand-rolled convention. + +**Proposed.** No unwinding (it would fight the AOT/no-runtime philosophy) — +sum-typed results with sugar, which falls straight out of G-06: + +```ludic +fn read_block(path: str) -> MapBlock ! IoError { + let f = file_open(path, "rb") else return IoError.NotFound + let n = try file_read(f, buf, 4096) # `try` propagates the error arm + return parse(buf[0..n]) +} + +match read_block(p) { + Ok(b) => use(b) + Err(e) => log_warn("block load failed", e) +} +``` + +#### G-10 · Generics (or monomorphised containers) + +Without some form of parametric types, every container is written N times. +Minimum viable: **compile-time monomorphisation over one type parameter**, no +constraints, no inference beyond the call site. + +```ludic +struct Vec[T] { data: []T, len: int, cap: int } + +fn push[T](v: Vec[T], x: T) -> void { + if v.len == v.cap { v.data = realloc(v.data, v.cap * 2) v.cap = v.cap * 2 } + v.data[v.len] = x + v.len = v.len + 1 +} + +var objects: Vec[entity] = vec_new[entity]() +``` + +**Work.** Parse `[T]` in decls and calls; a monomorphisation pass keyed on +(fn, concrete args) before codegen; name mangling. Deliberately *not* traits, +*not* variance, *not* HKT — this is a game language, and Luanti's C++ uses +templates in exactly this restrained way. + +#### G-11 · Hash maps + +**Luanti needs.** name→id for nodes and items (~60k entries), the definition +registries, `NodeMetaRef` string→string stores, groups (`string → int`), mod +storage, translation catalogues. + +**Proposed.** One monomorphised open-addressing map, in Ludic: + +```ludic +var by_name: Map[str, u16] = map_new[str, u16]() +by_name.set("default:stone", 1) +if let id = by_name.get("default:stone") { … } +for (k, v) in by_name { … } +``` + +### Tier 1 — ECS at world scale + +#### G-12 · The 1,024-entity ceiling + +**The number.** `compiler/native.c:18` — `#define LUDIC_MAX_ENT 1024`. Every +component becomes `@S_ = internal global [1024 x %Cmp_]`, plus a +`[1024 x i8]` presence array. Storage is **static, dense, and allocated for +every component whether used or not.** + +**What Luanti needs.** A busy server carries thousands of active objects; a +single 16³ MapBlock holds 4,096 nodes. Nodes must *not* be ECS entities (see +G-22), but mobs, items, players, particles, and node timers all should be. + +**Proposed.** Two changes, independent: + +1. **Configurable + dynamic capacity.** `game Foo { entities 65536 }` for the + static bound, and a growth path: component arrays become heap + `[]Cmp` that double. +2. **Sparse-set storage** (the standard ECS answer): per component a dense + packed array + a sparse index. Iteration cost becomes proportional to the + number of entities *with that component*, not to 1,024. This also kills the + memory waste: a component held by 10 entities stops costing 1,024 slots. + +```ludic +game Voxel { + entities 262144 # ceiling, or `dynamic` for growable + storage sparse # or `dense` for the current behaviour +} +``` + +#### G-13 · Runtime component attach/detach + +**Luanti needs.** An entity gains a nametag, loses physics, gets attached to a +vehicle, picks up an inventory — all at runtime. `ObjectRef:set_properties`, +`set_attach`, `set_armor_groups` are per-object mutations of the *shape* of the +entity. + +**Ludic has.** Components are attached only by `spawn`. There is no statement to +add or remove one afterwards. (Verified: no `attach`/`detach` in the parser.) +The `@H_` presence byte already exists — the storage supports it; the +*language* does not expose it. + +**Proposed.** + +```ludic +attach Nametag { text = "Zombie", color = 0xffffff } to e +detach Physics from e +if has Physics on e { … } +``` + +**Effort: S** — the runtime representation is already there. + +#### G-14 · Multiple ECS worlds + +Luanti runs a `ServerEnvironment` and a `ClientEnvironment` **in the same +process** for singleplayer. Ludic has exactly one implicit global world. + +```ludic +world Server { … } # separate component storage per world +world Client { … } +for (p) in Server.query [Pos] { … } +``` + +Also needed for: mapgen worker threads that build a block in isolation, and for +tests. + +#### G-15 · Query indices + +Today: `for (p) in query [Pos]` scans slots 0..1023 and re-tests the mask. +With G-12's higher ceilings that becomes the hot loop. Sparse sets (G-12) fix +the common case; the remaining need is **multi-component intersection** — pick +the smallest dense set and probe the others. + +#### G-16 · ABM-shaped systems — *where Ludic can beat Luanti* + +Luanti's ABM is a hand-rolled sampler in C++: pick random positions in loaded +blocks, test `nodenames`, test `neighbors`, roll `chance`, call a Lua closure. +It is one of the most-profiled parts of the engine. + +In Ludic this is a **declaration**: + +```ludic +system LavaCooling phase Update + every 10.0s # interval, not a hand-rolled timer + chance 1 in 50 # sampler, compiled in + nodes [C_LAVA_SOURCE] # content filter → an index, not a scan + near [C_WATER_SOURCE, C_WATER_FLOWING] + in y -32768 .. 32767 +{ + set_node(self_pos(), C_OBSIDIAN) +} +``` + +The compiler knows the node set at compile time, so it can build the per-block +content index once and iterate only matching positions — an optimisation Luanti +cannot do because its ABM predicates arrive as runtime strings. **This is the +strongest argument in the whole document for the language existing.** + +### Tier 2 — Platform + +#### G-17 · Threads, mutexes, atomics + +**Luanti needs.** `EmergeThread` × N (mapgen), `MeshUpdateThread` (client +meshing), `ConnectionSendThread` + `ConnectionReceiveThread`, the sound proxy +thread, and an async Lua job environment. `src/threading/` provides +`Thread`, `Mutex`, `Semaphore`, `Event`, `OrderedMutex`. + +**Ludic has.** Nothing. No `pthread_create` binding, no atomics, and — a real +problem — **`var` globals are unsynchronised i32 stores** and the ECS arrays are +process-global. + +**Proposed.** + +```ludic +thread pool emerge count 4 { # a named pool with a typed job queue + job Generate(bp: v3i) -> MapBlock { … } +} +emerge.submit(Generate(bp)) +if let blk = emerge.poll() { install(blk) } + +atomic var block_count: int = 0 +block_count.add(1) + +mutex map_lock +lock map_lock { … } + +channel Chan[MapBlock] results # MPSC, blocking or try_recv +``` + +Design steer: prefer **message passing + job pools** over shared mutable state, +because it composes with the ECS (a job owns its world slice) and because it is +what a determinism-oriented language should encourage. + +#### G-18 · Sockets + +UDP is mandatory (the whole protocol is UDP), TCP + TLS for the content store +and HTTP mods. + +```ludic +let s = udp_bind("0.0.0.0", 30000) +let (n, from) = s.recv(buf) +s.send_to(from, reply) +``` + +Bind at the syscall level from the runtime, as with `file_open` — `socket`, +`bind`, `sendto`, `recvfrom`, `poll`. No new language feature required beyond +G-01 (slices) and G-09 (errors), which is why this is M, not L. + +#### G-19 · Time + +`os_time()` returns whole seconds. A game loop needs a **monotonic** clock at +microsecond resolution, and Luanti's `DTIME_LIMIT = 2.5f` / fixed-timestep +stepping depends on it. + +```ludic +let t = now_us() # monotonic, u64 +sleep_ms(2) +``` + +#### G-20 · Dynamic loading + +`dlopen`/`dlsym` equivalents, so mods (G-25) can be loaded from a directory at +startup without relinking the engine. + +```ludic +let m = module_load("mods/farming/farming.dylib") +let init = m.symbol("mod_init") as fn(ModApi) -> void +``` + +#### G-21 · Compression + +**Luanti needs.** zstd for map format ≥29, zlib below it, and both directions. + +**Ludic has.** `runtime/native/inflate.ludic` — **decoder only** (verified: the +file implements `z_start`, `z_bits`, `z_table_build`, `z_decode`, `z_stored`; +there is no encoder). PNGs load; nothing can be written. + +**Proposed.** Write `deflate.ludic` (fixed-Huffman + LZ77 with a hash chain is +~300 lines and enough for map storage), and FFI to `libzstd` via `extern fn` for +the real thing. Both consistent with existing project practice. + +### Tier 3 — The voxel engine + +#### G-22 · A voxel chunk primitive + +This is the heart. **Nodes must not be ECS entities** — 36 million entities is +absurd, and Ludic's `entity` is an i32 index into parallel arrays. Voxels want +the opposite layout: dense, implicit position, no id. + +**Proposed** — make chunked volumes a first-class construct, the way `component` +is: + +```ludic +volume Map of MapNode chunk 16 { # 16³ chunks of MapNode + origin v3i # chunk coordinate + meta { generated: bool, timestamp: u32, lighting_complete: u16 } +} + +# indexing is bounds-safe and computes chunk + offset in one shot +let n = Map[pos] +Map[pos] = MapNode { param0 = C_STONE } + +# an explicit borrowed working area = Luanti's MMVManip / VoxelManip, +# which is how mapgen and bulk edits avoid touching the live map +manip vm = Map.borrow(pmin, pmax) +for p in vm.area { if vm[p].param0 == C_AIR { vm[p] = stone } } +vm.commit() # write back + relight + remesh +``` + +Mapped to Luanti: `Map` ≈ `ServerMap`, `chunk` ≈ `MapBlock`, `manip` ≈ +`MMVManip`, `vm.area` ≈ `VoxelArea`, and `commit()` ≈ +`blit_back + update_liquids + calc_lighting`. + +**Work.** L. Chunk table (hash map keyed on `v3i` — needs G-11), an allocator +for chunk payloads (G-08), the index arithmetic, and a loaded/unloaded state +machine. But note: this is *exactly* the kind of thing a domain-specific game +language should have, and no general-purpose language offers it. + +#### G-23 · Lighting & meshing + +**Lighting.** Luanti propagates two banks (day/night) via BFS flood fill across +block boundaries (`voxelalgorithms.cpp`, 1,309 LOC), with the 12-bit +`lighting_complete` mask tracking which faces are still provisional. + +**Meshing.** `content_mapblock.cpp` (1,870 LOC) emits geometry per drawtype; +`mapblock_mesh.cpp` builds the buffers; `mesh_generator_thread.cpp` does it off +the main thread. + +**Proposed.** Both stay *library* code written in Ludic — but they need G-01 +(vertex arrays), G-04 (float vertex data for the GPU), G-17 (mesh threads), and +G-28 (somewhere to send the buffers). Language-level help worth adding: + +```ludic +# a declarative face-culling rule set, instead of 19 hand-written branches +drawtype Normal { + cull when neighbor.solid + faces cube tiles [top, bottom, left, right, front, back] +} +drawtype Plantlike { faces cross scale visual_scale cull never } +``` + +#### G-24 · Collision, raycast, AABB + +Swept AABB against the node grid + other objects, with `stepheight`; a voxel +DDA raycast for pointing; A* over the node grid for mob pathing (1,419 LOC). + +All expressible in Ludic **once G-04 (wide numbers) and G-07 (`sqrt`) exist.** +No new language feature needed — this is library work, ~2,000 lines. + +### Tier 4 — Extensibility + +#### G-25 · The mod model — the hard architectural call + +**The problem.** Luanti's entire value proposition is that a server operator +drops a folder into `mods/` and restarts. 321 `core.*` functions exist to serve +that. Ludic is AOT-compiled, and the project constraint is explicit: **no VM, +no interpreter, no scripting language, ever.** + +These are not reconcilable by adding Lua. They *are* reconcilable, and the +answer is already half-built in the repo — `ludicc lib.ludic --shared -o +lib.dylib` and `extern fn … = "symbol"`. + +**Proposed: compiled mods behind a stable C-ABI interface.** + +```ludic +# mods/farming/farming.ludic +mod Farming { + version 1 + depends ["core"] + + on init(api: ModApi) { + api.register_node("farming:wheat_1", NodeDef { + drawtype = DrawType.Plantlike, + tiles = ["farming_wheat_1.png"], + groups = [("snappy", 3), ("flammable", 2)], + walkable = false, + buildable_to = true, + }) + + api.register_abm(Abm { + nodes = ["farming:wheat_1"], + interval = 20.0, chance = 20, + action = grow_wheat, + }) + } +} +``` + +Built with `ludicc mods/farming/farming.ludic --shared -o mods/farming/farming.dylib`, +loaded at startup via G-20, and talking to the engine only through a versioned +`ModApi` vtable. + +**What you gain over Lua:** mods run at native speed (Luanti's ABMs and +`on_generated` handlers are its top profiler entries, and they are all Lua); +mod errors are compile-time; the ECS is available to mods directly. + +**What you lose, and must decide about:** +- **No hot reload** without process restart (mitigable: reload the dylib). +- **No sandbox.** Lua's `s_security.cpp` confines mods to their own directory; + a native dylib can do anything. Options: (a) accept it, like Factorio pre-2.0 + or any C++ plugin system; (b) run mods in a subprocess with an IPC boundary; + (c) restrict the `ModApi` surface and ship signed mods. +- **Distribution.** Mods become per-platform binaries, or ship as source and + compile on first load (`ludicc` is 2,508 lines — shipping it *is* viable). + +**My recommendation:** ship-as-source + compile-on-load. It keeps the "drop a +folder in" workflow, keeps everything in one language, needs no VM, and turns +`ludicc`'s small size into a genuine architectural advantage. + +#### G-26 · Definition tables & registries + +Luanti registers definitions from Lua tables at runtime. Ludic has no table +literal, no runtime registry, and no way to name 60,000 content ids. + +**Proposed** — a declarative `def` construct that is data at compile time *and* +registrable at runtime: + +```ludic +def node Stone { + name = "default:stone" + drawtype = DrawType.Normal + tiles = ["default_stone.png"] + groups = [("cracky", 3)] + is_ground_content = true + sounds = SoundSet.Stone + drop = "default:cobble" +} +``` + +The compiler assigns content ids, emits the table as static data, and the +registry maps `str → u16` at load (G-11). Mod-supplied defs go through the same +path at runtime. + +#### G-27 · Metadata + +`NodeMetaRef` / `ItemStackMetaRef` / `PlayerMetaRef`: string→string stores +attached to positions, stacks, and players, with an "inventory" attached to node +meta. Needs G-03 and G-11; then it is straightforward library code. + +### Tier 5 — Graphics & UI + +#### G-28 · The GPU + +Luanti bundles an **87,554-line Irrlicht fork** to get: OpenGL 3 / GLES2 / +WebGL contexts, vertex + index buffers, texture management with mipmaps and +atlases, a material/shader system, scene graph, frustum culling, and mesh +loaders (B3D, OBJ, glTF). On top of that sit 20 GLSL programs. + +Ludic has a 320×240 software framebuffer presented through +`runtime/native/cocoa.ll` (327 lines of hand-written LLVM IR calling +`objc_msgSend`). + +**This is the largest single gap in the document.** Options: + +| Option | Cost | Fit with constraints | +|---|---|---| +| Software rasteriser in Ludic | L | ✅ perfect — but ~5 fps at 720p for voxels | +| Bind OpenGL/Metal via `extern fn` | M | ✅ same posture as zlib FFI; **recommended** | +| Hand-written IR per platform, like `cocoa.ll` | XL | ✅ but repeated per API | +| Write a GPU driver | ✗ | not serious | + +**Recommended:** treat the GPU exactly as the project already treats the OS — +an ABI to call, not a C program to compile. `extern fn glDrawElements(…) = +"glDrawElements"`, with a thin `runtime/native/gfx3d.ludic` over it. This is +consistent with the existing rule ("C libraries are used via FFI") and needs +**no compiler change beyond G-04's `f32`.** + +#### G-29 · 3D math types + +```ludic +struct v3f { x: f32 = 0, y: f32 = 0, z: f32 = 0 } +struct m4 { m: [16]f32 } +struct aabb { min: v3f, max: v3f } + +fn dot(a: v3f, b: v3f) -> f32 +fn cross(a: v3f, b: v3f) -> v3f +fn normalize(v: v3f) -> v3f +fn look_at(eye: v3f, at: v3f, up: v3f) -> m4 +fn perspective(fovy: f32, aspect: f32, znear: f32, zfar: f32) -> m4 +``` + +Worth considering: **operator overloading for vector types only** — Ludic +currently forbids overloading entirely, and `a + b` on vectors is the one place +where the ban costs real readability. A narrow, built-in-types-only exception is +defensible. + +#### G-30 · UI at formspec scale + +Ludic's `ui` block is architecturally right and 8 widgets deep. Formspec is 64 +elements. The gap that matters most: + +| Missing | Why it blocks Luanti | +|---|---| +| `field` / `textarea` / `pwdfield` | no text input at all — no chat, no sign editing | +| `list` (inventory slots) | the core interaction of the game | +| `scroll_container` / `scrollbar` | any inventory bigger than a screen | +| `table` / `textlist` | server list, mod manager | +| `dropdown`, `checkbox`, `tabheader` | settings | +| `model` | 3D item preview | +| `style[]` / `style_type[]` | theming | +| mouse input | **Ludic's UI is keyboard-only today** (`ui_tick(key())`) | +| `hypertext` markup | formatted text | + +### Tier 6 — Audio & i18n + +#### G-31 · Audio + +Nothing exists. Needed: a mixer, Ogg Vorbis decode (or ship a simpler codec), +3D panning + attenuation, and an audio callback thread (G-17). Consistent with +project practice: decode in Ludic (as PNG and TrueType already are), bind +CoreAudio/ALSA/WASAPI via `extern fn`. + +```ludic +let s = sound_load("assets/dig_stone.ogg") +sound_play(s, SoundSpec { gain = 0.8, pitch = 1.0, pos = p, max_hear = 32.0 }) +``` + +#### G-32 · i18n + +Luanti: gettext, plural forms (`gettext_plural_form.cpp`), per-server +translation files (`.tr`), and escape-sequence-based inline translation. Ludic +has UTF-8 rendering (good) and no translation machinery. Needs G-03 and G-11. + +### Tier 7 — Persistence & network + +#### G-33 · Persistence + +Ludic's `save()`/`load()` writes **the entire ECS world** in one blob. Luanti +needs per-block, versioned, compressed, incrementally-written storage keyed in +SQLite, plus player files, auth, and mod storage. + +```ludic +serialize MapBlock version 29 { + u8 version + u8 flags + u16 lighting_complete + u32 timestamp + map name_id: Map[u16, str] + zstd { # everything inside is compressed + array param0: [4096]u16 bigendian + array param1: [4096]u8 + array param2: [4096]u8 + list metadata + list timers + list static_objects + } +} +``` + +A declarative `serialize` block generating both encoder and decoder would be a +strong Ludic feature — it is exactly the kind of error-prone, symmetric, +version-tagged code that a game language should generate rather than hand-write. + +#### G-34 · Networking + +90 packet types, reliable UDP with split packets and ack windows, and priority +block streaming. Depends on G-17, G-18, G-21, G-33. The packet definitions +themselves fall out of `serialize` (G-33) + `union` (G-06): + +```ludic +packet ToClient { + BlockData = 0x20 { pos: v3i, block: MapBlock } + AddParticle = 0x46 { … } + ActiveObjectMessages = 0x31 { msgs: []ObjectMsg } +} +``` + +--- + +## 6. Roadmap + +Ten milestones. Each one **ends in something runnable** — that is the rule; no +milestone is "add a type system feature" with nothing to show. Effort estimates +assume one developer and are deliberately conservative. + +### M0 — Language core, part 1: aggregates *(≈6 weeks)* +> **Gates:** G-01 arrays/slices · G-02 structs · G-05 sized ints + +**Demo:** rewrite `runtime/native/image.ludic`'s PNG decoder to use +`[]u8` and `struct Pixel` instead of `mem_alloc` + `peek8`. Same output PNG, +half the lines, bounds-checked. + +**Why first:** every other item in this document is blocked on it. The existing +runtime is the perfect proving ground — it is 3,700 lines of exactly the +hand-rolled pointer arithmetic these features exist to delete. + +```ludic +# before (runtime/native/image.ludic today) +fn px(img: ptr, x: int, y: int, w: int) -> int { return peek32(img, (y*w+x)*4) } + +# after +struct Rgba { r: u8, g: u8, b: u8, a: u8 } +fn px(img: []Rgba, x: int, y: int, w: int) -> Rgba { return img[y*w + x] } +``` + +### M1 — Language core, part 2: numbers, strings, errors *(≈6 weeks)* +> **Gates:** G-03 strings · G-04 `f32`/`fixed64` · G-06 enums/unions · G-07 math · G-09 errors + +**Demo:** a `noise.ludic` implementing Luanti's `NoiseFractal3D` exactly, and a +headless program that renders a 512×512 heightmap PNG from it. Compare against +Luanti's own output for the same seed — **bit-comparable terrain is the +acceptance test.** + +This is the milestone that closes the coordinate bug (G-04). Worth writing the +regression test first: + +```ludic +system CoordRange phase Start { + let far: fixed64 = 310070.0 # would wrap in Q16.16 + assert(flr64(far) == 310070) + let d = far * far # 9.6e10 — must not wrap +} +``` + +### M2 — Platform *(≈5 weeks)* +> **Gates:** G-17 threads · G-19 time · G-18 sockets · G-20 dynamic loading · G-21 deflate encode + +**Demo:** a headless Ludic program that spawns 4 worker threads, each generating +a 16³ noise chunk, deflate-compresses it, writes it to a file, and a second +process that reads it back — proving the thread pool, the compressor and the +round-trip. + +**Note on the new WASM target.** A peer session just landed WebAssembly support +(`runtime/web/`, `test.sh` now 64/64), and `@main` is now split into +`ludic_boot/frame/alive/teardown` so a browser can drive the loop from +`requestAnimationFrame`. Two consequences for this roadmap: (a) threads on +wasm32 mean Web Workers + SharedArrayBuffer, not pthreads, so **G-17 needs a +per-target backend from day one**; (b) `size_t` is `i32` on wasm — new +intrinsics must go through `ll_size_t()`/`ll_widen()`/`ll_narrow()`, which +matters for every slice and array intrinsic added in M0. + +### M3 — The voxel primitive *(≈8 weeks)* +> **Gates:** G-11 maps · G-12 ECS scale · G-13 attach/detach · G-22 `volume`/`manip` + +**Demo:** **a flat 3D world you can fly through**, still software-rendered at +320×240 — a chunked `volume Map of MapNode chunk 16`, chunks generated on the +worker pool from M2, a free camera, and a simple raycast rasteriser for +visualisation. Ugly, slow, and unambiguously a voxel engine. + +```ludic +volume Map of MapNode chunk 16 { origin v3i meta { generated: bool } } + +system Generate phase Update { + for bp in pending_chunks() { + manip vm = Map.borrow_chunk(bp) + for p in vm.area { + let h = flr(noise2d(fx(p.x) / 64.0, fx(p.z) / 64.0) * 24.0) + 8 + vm[p] = if p.y <= h { NODE_STONE } else { NODE_AIR } + } + vm.commit() + } +} +``` + +### M4 — GPU + 3D *(≈10 weeks)* +> **Gates:** G-28 GPU FFI · G-29 3D math · G-23 meshing/lighting + +**Demo:** the M3 world, **textured, lit and running at 60 fps** — greedy or +per-face meshing on a worker thread, day/night light banks propagated by BFS, +one shader program, a texture atlas from the existing PNG decoder. + +This is where the project stops being a 2D game language and becomes capable of +Luanti's genre. It is also the milestone with the most schedule risk — bind +OpenGL 3.3 via `extern fn` first (Metal/WebGL later) and resist the temptation +to write a scene graph. + +### M5 — Interaction *(≈6 weeks)* +> **Gates:** G-24 collision/raycast · G-30 UI (input, lists, scroll) · mouse input + +**Demo:** **you can walk, jump, dig and place.** Swept-AABB player physics with +`stepheight`, a DDA raycast for pointing, a hotbar, and an inventory screen with +draggable slots. This is the first milestone that is *playable*. + +### M6 — Definitions & registries *(≈5 weeks)* +> **Gates:** G-26 `def` blocks · G-27 metadata · G-16 ABM systems + +**Demo:** 30 node types and 10 item types declared with `def node` / `def item`, +groups-based dig times, a chest with node metadata and an inventory, and lava +that cools into obsidian via an ABM-shaped system. **This is the milestone where +the language's ECS finally pays off visibly.** + +### M7 — Persistence *(≈4 weeks)* +> **Gates:** G-33 `serialize` blocks · SQLite via FFI + +**Demo:** quit and relaunch; the world, your inventory and your position are +exactly as you left them. Blocks written incrementally, zstd-compressed, keyed +by interleaved position — read Luanti's own `map.sqlite` as a compatibility +stretch goal. + +### M8 — The mod ABI *(≈8 weeks)* +> **Gates:** G-25 mod model · G-20 loading · a versioned `ModApi` + +**Demo:** a `mods/farming/` folder containing only `.ludic` source and textures; +drop it in, restart, and wheat exists — compiled on first load, cached as a +dylib. Then delete the folder and it is gone. **This is the milestone that makes +it Luanti rather than a voxel game.** + +### M9 — Multiplayer *(≈12 weeks)* +> **Gates:** G-34 protocol · G-14 multiple worlds · G-18 sockets + +**Demo:** two clients, one server, on separate machines: block changes, +movement, chat, and inventory sync. Client and server in one binary via +`world Server` / `world Client` (G-14) so singleplayer is just a loopback. + +### Audio & i18n *(fold into M5–M8 opportunistically)* +> **Gates:** G-31 · G-32 + +### Timeline summary + +| Milestone | Effort | Cumulative | Ends with | +|---|---|---|---| +| M0 aggregates | 6 wk | 6 wk | runtime rewritten on arrays/structs | +| M1 numbers/strings | 6 wk | 12 wk | Luanti-comparable noise terrain | +| M2 platform | 5 wk | 17 wk | threaded, compressed chunk I/O | +| M3 voxel primitive | 8 wk | 25 wk | flyable 3D voxel world | +| M4 GPU | 10 wk | 35 wk | textured, lit, 60 fps | +| M5 interaction | 6 wk | 41 wk | **playable: walk, dig, place** | +| M6 definitions | 5 wk | 46 wk | modded content, ABMs | +| M7 persistence | 4 wk | 50 wk | worlds that survive restart | +| M8 mod ABI | 8 wk | 58 wk | **drop-in mods** | +| M9 multiplayer | 12 wk | 70 wk | two clients, one server | + +≈**70 developer-weeks** to a Luanti-class engine written in Ludic. For scale: +Luanti itself is 362,258 lines accumulated since 2010. + +--- + +## 7. Decisions I need from you + +These change the shape of the work and are yours to make, not mine. My +recommendation is given first in each case. + +1. **Numerics: `fixed64` *and* `f32`, or just `f32`?** + *Recommendation: both.* `fixed64` for gameplay/physics (deterministic + lockstep multiplayer is a real advantage, and Luanti's float physics is a + known source of desync); `f32` for noise and GPU vertex data, where it is + non-negotiable. + +2. **Mod distribution: source-and-compile-on-load, or prebuilt binaries?** + *Recommendation: source.* `ludicc` is 2,508 lines — shipping the compiler + with the game preserves the "drop a folder in" workflow that is Luanti's + entire ecosystem, keeps one language end-to-end, and needs no VM. + +3. **Mod sandboxing: accept native trust, or subprocess isolation?** + *Recommendation: accept it for M8, revisit before any public server.* + Luanti's `s_security.cpp` is 1,253 lines of Lua-specific confinement that has + no native analogue; subprocess + IPC is the only real answer and it is a + quarter of work on its own. + +4. **GPU: FFI to OpenGL, or hand-written IR per platform like `cocoa.ll`?** + *Recommendation: FFI.* It matches the project's existing posture toward + libraries, and `cocoa.ll` is 327 lines for *five* window functions — OpenGL + has hundreds of entry points. + +5. **Compatibility: read Luanti's `map.sqlite` and speak protocol 37+, or a + clean-room format?** *Recommendation: clean room, with a one-way importer.* + Wire compatibility means implementing 90 packet types before anything is + playable; it inverts the whole milestone order. + +6. **Scope: the full engine, or a Luanti-shaped game?** Worth being honest with + yourself here. M0–M6 (≈46 weeks) gets a genuinely good single-player voxel + game and, more importantly, **makes Ludic a language that could plausibly + build one.** M8–M9 are what make it *Luanti*, and they are half the budget. + +--- + +## 8. Appendix A — target state + +What `examples/voxel.ludic` would look like once M0–M6 land. This is the +document's thesis in one file: nothing here is expressible today, and all of it +is ordinary Ludic in shape. + +```ludic +game Voxel { + import "voxel/nodes.ludic" + import "voxel/worldgen.ludic" + + # ---- data --------------------------------------------------------------- + struct MapNode { param0: u16 = 0, param1: u8 = 0, param2: u8 = 0 } + struct v3i { x: int = 0, y: int = 0, z: int = 0 } + struct v3f { x: f32 = 0, y: f32 = 0, z: f32 = 0 } + + volume Map of MapNode chunk 16 { + origin v3i + meta { generated: bool = false, timestamp: u32 = 0 } + } + + component Body { pos: v3f, vel: v3f, aabb: aabb, on_ground: bool = false } + component Look { yaw: f32 = 0, pitch: f32 = 0 } + component Health { hp: int = 20, max: int = 20 } + component Inv { slots: [32]ItemStack } + + archetype Player { Body, Look, Health, Inv } + archetype Mob { Body, Look, Health } + + # ---- content ------------------------------------------------------------ + def node Stone { + name = "voxel:stone" drawtype = DrawType.Normal + tiles = ["stone.png"] groups = [("cracky", 3)] + is_ground_content = true drop = "voxel:cobble" + } + def node Water { + name = "voxel:water" drawtype = DrawType.Liquid + tiles = ["water.png"] liquid = Liquid.Source { alt_flowing = "voxel:water_flowing" } + walkable = false light_propagates = true + } + + # ---- generation, off the main thread ------------------------------------ + thread pool emerge count 4 { + job Generate(bp: v3i) -> Chunk { + manip vm = Map.stage(bp) + for p in vm.area { + let n = noise2d(p.x as f32 / 64.0, p.z as f32 / 64.0, seed()) + let h = flr(n * 24.0) + 8 + vm[p] = if p.y > h { NODE_AIR } + else if p.y == h { NODE_GRASS } + else { NODE_STONE } + } + return vm.finish() + } + } + + system Emerge phase Update { + for bp in Map.wanted(view_radius = 10) { emerge.submit(Generate(bp)) } + while let c = emerge.poll() { Map.install(c) relight(c) remesh(c) } + } + + # ---- simulation: an ABM as a first-class system ------------------------- + system LavaCooling phase Update + every 10.0s chance 1 in 50 + nodes [NODE_LAVA_SOURCE] near [NODE_WATER_SOURCE, NODE_WATER_FLOWING] + { Map[self_pos()] = NODE_OBSIDIAN } + + # ---- physics ------------------------------------------------------------ + system Physics phase FixedUpdate + query (b) [Body] + { + b.vel.y = b.vel.y - 9.81 * dt() + let r = collide_swept(Map, b.aabb, b.pos, b.vel * dt(), stepheight = 0.6) + b.pos = r.pos + b.on_ground = r.hit_floor + if r.hit_floor { b.vel.y = 0.0 } + } + + # ---- interaction -------------------------------------------------------- + system Dig phase Input + query (b, l) [Body, Look, {Player}] + { + when mouse_pressed(MOUSE_LEFT) { + match raycast(Map, eye(b), dir(l), 5.0) { + Pointed.Node(under, _) => { + let def = node_def(Map[under].param0) + give(self(), def.drop) + Map[under] = NODE_AIR + } + _ => {} + } + } + } + + # ---- render ------------------------------------------------------------- + scene InGame start { + layer World { + system DrawWorld phase Render { + gfx_begin(camera_of(local_player())) + for c in Map.visible(frustum()) { gfx_draw_mesh(c.mesh) } + gfx_end() + } + } + layer Hud { + system DrawHud phase Render { ui_render() } + } + } +} +``` + +**Read that against LANGUAGE.md.** The `system`/`query`/`phase`/`scene`/`layer` +/`archetype`/`match` skeleton is *unchanged* — every line of new capability is +either a type (`struct`, `f32`, `[]T`, `enum`) or one of four new constructs +(`volume`, `manip`, `thread pool`, `def`). That is the encouraging finding of +this whole exercise: **Ludic's programming model is already the right one for +this game. What is missing is underneath it, not around it.** + +--- + +## 9. Appendix B — what Ludic already has that Luanti had to build + +Not everything is a deficit. Ludic starts with several things Luanti spent years +acquiring, and they should be counted: + +| Ludic has | Luanti equivalent | Cost Luanti paid | +|---|---|---| +| ECS in the language (`component`/`query`/`system`/`phase`) | hand-rolled `ActiveObjectMgr` + ad-hoc containers | scattered across `serverenvironment.cpp` (2,091) + `activeobjectmgr` | +| `scene`/`layer` state machine | mode flags and `if` ladders in `game.cpp` | part of 3,815 LOC | +| `match`/`machine`/`become` | switch chains | — | +| Retained `ui` tree as data | formspec **string DSL** parsed at runtime | `guiFormSpecMenu.cpp`, **5,610 LOC** | +| TrueType engine written in-language | FreeType + `CGUITTFont.cpp` (1,003) | external dep | +| PNG + DEFLATE decode in-language | libpng + zlib | external deps | +| Deterministic RNG in the language | `PcgRandom`/`PseudoRandom` exposed to Lua | — | +| Compile-time type checking of game logic | Lua: runtime errors on a live server | the entire class of mod crashes | +| One language for engine *and* content | C++ engine + Lua mods + a 1,253-line sandbox | the whole `src/script/` tree, **34,240 LOC** | + +That last row is the strategic one. **A third of Luanti's engine — 34,240 lines +of `src/script/` plus 22,634 lines of `builtin/` Lua — exists solely to bridge +C++ and Lua.** A Ludic implementation with a compiled mod ABI (G-25) does not +need that bridge at all. Roughly 57,000 lines of Luanti are a tax that Ludic +would simply not pay. + +--- + +## 10. Verdict + +**Can Ludic implement Luanti today?** No — and not because of anything about +games. It is missing arrays, strings, structs, floats, threads and sockets. Any +language missing those cannot implement any large program. + +**Is Ludic's design wrong for Luanti?** No — and this is the more interesting +answer. The ECS-in-the-language model, phases, scenes, archetypes and `match` +are a *better* fit for a voxel sandbox than C++-plus-Lua is. The `system … every +10.0s chance 1 in 50 nodes […]` form (G-16) compiles to something Luanti's ABM +implementation cannot achieve, because Luanti's predicates arrive as strings at +runtime and Ludic's arrive at compile time. + +**What is the actual shortest path?** M0 and M1. Arrays, structs, strings, +floats. Twelve weeks that convert Ludic from a language that can express a +2D JRPG into one that can express an engine — after which every remaining gap in +this document is ordinary library work in Ludic, plus one hard call about mods +(G-25) and one large push on the GPU (G-28). + +--- + +*Generated from `luanti-org/luanti@main` (362,258 LOC surveyed) against +`ludicc` at `compiler/{ludicc,native,driver}.c` and `runtime/native/*.ludic`. +Every Ludic limitation cited was verified by reading the compiler or by +compiling a probe program, not inferred from documentation.* diff --git a/README.md b/README.md new file mode 100644 index 00000000..200d8376 --- /dev/null +++ b/README.md @@ -0,0 +1,180 @@ +# Ludic + +An AI-first, ahead-of-time **compiled** game language with an ECS core, a +deterministic fixed-point runtime, and a native 2D backend. `ludicc` lowers +Ludic to LLVM IR itself and emits a native binary — **and `ludicc` is itself +written in Ludic.** + +``` + .ludic ──► ludicc ──► LLVM IR ──► object ──► native binary + (in Ludic) +``` + +**No C is generated, compiled or linked anywhere in a build.** There is no +interpreter, no transpiler, and no C runtime: the framebuffer, sprites, PNG +decoding, TrueType text, the retained UI, the registers and the RNG are all +written in Ludic (`runtime/native/*.ludic`), and the macOS window is +hand-written LLVM IR (`runtime/native/cocoa.ll`). Beneath that sits only the +platform's own ABI — malloc, fwrite, objc_msgSend, CoreGraphics — reached by +compiler intrinsics, the same floor Rust and Swift stand on. + +**The compiler is written in Ludic.** `selfhost/*.ludic` is a Ludic compiler — +lexer, parser and LLVM-IR backend — that compiles every example (including the +6-file JRPG) to the byte-exact same binary the original C compiler produced, and +compiles **its own source** to a fixpoint. It is built from a checked-in IR seed +(`selfhost/ludicc.seed.ll`) with clang alone; run `./selfhost/bootstrap-cfree.sh` +to rebuild it with no C compiler in the loop. The former C compiler is gone. + +Neither the compiler nor the games are C. Beneath both sits only the platform's +own ABI — malloc, fwrite, objc_msgSend, CoreGraphics — reached by intrinsics, the +same floor Rust and Swift stand on. (The wasm/cross-compile/shared-library driver +paths lived in the old C compiler and are not yet re-implemented on the +self-hosted native toolchain.) + +## Layout + +| Path | What it is | +|------|-----------| +| `selfhost/*.ludic` | **the compiler, written in Ludic** — lexer, parser, and the LLVM-IR backend (ECS storage, queries, spawn, `match`/`machine`, UI, scenes, save/load, fixed-point). Concatenated by `selfhost/build.sh`; built from `selfhost/ludicc.seed.ll` | +| `selfhost/bootstrap-cfree.sh` | rebuild the compiler from the IR seed with **no C compiler**, and prove it reproduces its own IR | +| `runtime/native/core.ludic` | the runtime written *in Ludic* for the native path (framebuffer, text, registers, RNG, input) | +| `COMPILING.md` | the native pipeline: `ludicc → LLVM IR → exe/dylib`, `module`/`export`, cross-compilation, `rt_*` intrinsics | +| `runtime/native/image.ludic` | PNG decoding, images, sprites, alpha blending and 9-slice — in Ludic | +| `runtime/native/inflate.ludic` | DEFLATE decompression (RFC 1951), so PNG needs no zlib on any target | +| `runtime/native/truetype.ludic` | from-scratch TrueType loader + antialiased glyph rasterizer, in Q16.16 | +| `runtime/native/ui.ludic` | retained UI widget tree: layout, 9-slice, focus, events — in Ludic | +| `runtime/native/cocoa.ll` | the macOS window, written in LLVM IR (Objective-C runtime + CoreGraphics via their C ABI) | +| `runtime/web/wasm.ll` | the web's platform layer in LLVM IR: the allocator, bulk memory and strings, since wasm32 has no libc | +| `runtime/web/platform.js` | the browser's window — the same five `win_*` functions `cocoa.ll` implements, against a `` | +| `runtime/web/index.html` | the page a web build is served from | +| `tools/ludic-web/run.mjs` | runs a headless wasm build under Node, so native and wasm output can be diffed | +| `examples/chronorift.ludic` | the JRPG written in Ludic (multi-file via `import`, archetype-based) | +| `examples/menu.ludic` | a retained-UI title screen (9-slice, TrueType, focusable buttons) | +| `examples/snake.ludic` | a second, unrelated game — proves the language is general (same toolchain, no engine hardcoding) | +| `build.sh` | `./build.sh examples/.ludic` | +| `test.sh` | regression suite: builds the compiler, compiles/runs all examples, checks save/load + diagnostics (`./test.sh`) | +| `tools/ludic-tools/` | the editor toolchain, in C: `ludic-fmt` (source formatter) and `ludic-lsp` (language server) — one lexer and one vocabulary shared by both | +| `tools/editors/` | plugins for VS Code and JetBrains, plus configuration for Neovim, Helix, Emacs, Sublime and Zed ([README](tools/editors/README.md)) | +| `tools/test-tools.sh` | regression suite for the toolchain: proves formatting never changes a program, drives the language server over real LSP traffic | + +## Build & run + +`ludicc` compiles Ludic straight to machine code via LLVM IR. See +**[COMPILING.md](COMPILING.md)** for the pipeline, shared libraries +(`--shared`), cross-compilation and the runtime protocol. + +```bash +./build.sh examples/chronorift.ludic +./build/chronorift # opens a native window +``` + +Headless render (for testing / CI): + +```bash +./build.sh examples/chronorift.ludic --headless +printf 'ddddwww' | ./build/chronorift_headless # writes out.ppm +sips -s format png out.ppm --out frame.png +``` + +A `module` compiles to a shared library instead of a program: + +```bash +./build.sh examples/lib/combat.ludic --lib # -> build/libcombat.dylib +``` + +In a browser: + +```bash +./build.sh examples/chronorift.ludic --web # -> build/web/ +python3 -m http.server -d build/web 8000 # open http://localhost:8000/ +``` + +`build/web/` is a self-contained 116 KB directory — the 42 KB module, the loader, +a page, and the sprites the compiler saw the game name. Copy it to any static +host and it runs; it needs no server-side anything and no special headers. Saves +go to `localStorage`, so `save()`/`load()` survive a reload. + +A wasm build needs an LLVM with the WebAssembly backend and `wasm-ld` — Linux +`clang`/`lld` have both, Apple's clang has neither (`brew install llvm lld`). +See **[COMPILING.md](COMPILING.md#the-web)** for the pipeline, who owns the frame +loop, and how assets are bundled. + +## Editor support + +```bash +./tools/build-tools.sh # -> build/ludic-fmt, build/ludic-lsp +``` + +`ludic-lsp` speaks LSP 3.17 over stdio, so one binary serves every editor: +completion that knows whether you are after a `.`, inside a `query [...]` or in +a `ui` block; diagnostics from the compiler itself; go-to-definition and rename +across `import`ed files; comment-preserving formatting. `ludic-fmt` is the same +formatter as a CLI, for pre-commit hooks and CI. + +Plugins for **VS Code** and **JetBrains IDEs** (Community editions included) and +drop-in configuration for Neovim, Helix, Emacs, Sublime and Zed are in +[`tools/editors/`](tools/editors/README.md). Both tools also understand +```` ```ludic ```` fences in Markdown, so this file and `LANGUAGE.md` get the +same highlighting, checking and formatting as the source tree. + +## Language features implemented + +- `component` (typed fields + defaults), `system` (`phase`, `@annotations`, + `reads`/`writes` clauses), `const`, `fn` (with `requires`/`ensures` parsed). +- `archetype` — named entity **kinds** (bundles of components); identity is one + int per entity, replacing empty tag components. Filter with `{Kind}`. +- `import "file"` — multi-file programs (fragments spliced in, include-guarded, + per-file diagnostics). +- ECS queries: `for (a, b) in query [A, B, {Tag}] where { … }`. +- `spawn`/`despawn` with entity-slot reuse; nested queries. +- Control flow: `if`/`else`, `when`, `while`, numeric `for i in a .. b`. +- Types: `int`, `fixed` (Q16.16, with correct `*`/`/` lowering), `bool`, + `entity`, `str`. Fixed-point vs int arithmetic is resolved by the typechecker. +- Deterministic seeded RNG; `save()`/`load()` snapshot of the whole ECS World. +- 2D primitives: `clear`, `fill_rect`, `frame_rect`, `put_px`, `present`, `key`. +- TrueType text (`font_load`, `text_ttf`) with full Unicode + anti-aliasing; + arbitrary-size images + `draw_9slice`. +- `ui` — a retained widget tree declared as data (panels, labels, buttons, + images; layout, 9-slice skins, keyboard focus + click events). +- `match` / `machine`+`state`+`become` — dispatch and state machines. +- `scene` / `layer` / `enter` — mutually-exclusive game states, each with + `on enter`/`on exit` hooks and layered systems (layer order = draw order). +- `var` — typed module-level state, included in save/load snapshots. +- `module` + `export fn` — compile a .ludic file to a shared library whose + exported functions are ordinary C-ABI symbols. +- `extern fn … = "symbol"` — call any C-ABI library, Ludic or otherwise. +- `--target wasm32-unknown-unknown` — the same game in a browser: the runtime, + the ECS and the graphics stack compiled to wasm, rendering frames identical to + the native build's. + +## The game: Chrono Rift + +A playable co-op JRPG in `examples/chronorift.ludic`, using CC0 +[Kenney](https://kenney.nl) sprites (Tiny Town + Tiny Dungeon), decoded from +PNG at runtime by the Ludic-written PNG/DEFLATE decoder — no zlib, no external +dependency on any target. + +Controls: +- **Overworld:** `WASD` move, `K` save, `L` load. +- **Battle (local co-op):** Player 1 / Knight — `W`/`S` select, `Space` confirm. + Player 2 / Mage — `I`/`K` select, `J` confirm. Each player takes their own + turn each round (Attack / Defend / Run; Mage has Attack / Heal / Defend). + +## Status + +- [x] Compiler pipeline: Ludic → LLVM IR → native binary / shared library +- [x] No C generated, compiled or linked in a build; runtime written in Ludic +- [x] Cross-compilation to ELF (x86-64, aarch64) and Windows COFF +- [x] ECS runtime (components, systems, phases, queries, entity pooling) +- [x] Windowed 2D rendering (Cocoa driven from LLVM IR) + headless PPM verification +- [x] CC0 Kenney PNG sprites (`load_png`, decoder written in Ludic) + scrolling camera +- [x] Overworld: tilemap, movement, collision +- [x] Random encounters + turn-based battle (HP/MP, seeded-RNG damage) +- [x] Party + **local co-op** (P1 Knight, P2 Mage, per-player turns) +- [x] Leveling (XP → stat growth) and game-over / respawn +- [x] **Self-hosting**: a Ludic-written compiler compiles its own source to a byte-exact fixpoint, and rebuilds itself from a checked-in IR seed with no C compiler in the loop (`selfhost/`, `./selfhost/bootstrap-cfree.sh`) +- [x] Snapshot save / load (full ECS World) +- [x] Two maps (overworld + dungeon) with map switching via the arch +- [x] Boss encounter (Rift Warden) + victory condition +- [x] Item shop (gold → potions) at the house; potions usable in battle (Knight ITEM) +- [ ] More skills / enemy variety (future) diff --git a/SYNTAX-REDESIGN.md b/SYNTAX-REDESIGN.md new file mode 100644 index 00000000..5c892a29 --- /dev/null +++ b/SYNTAX-REDESIGN.md @@ -0,0 +1,254 @@ +# Ludic Syntax Redesign — Cohesion Pass + +A plan to make Ludic's syntax internally consistent. It fixes the drift between +the spec and the compiler, then unifies the grammar around two rules. Scope: +**full redesign (Phases 0–5)**. Named-field direction: **colon everywhere**. + +> Status: **Phase 1 landed** (see below). Phases 2→5 are proposals. The phases +> are ordered so the documentation never describes syntax the compiler rejects, +> and every phase ends with the compiler still self-hosting to a fixpoint +> (`./test.sh`). +> +> Coordinated with the toolchain agent (CLI front-end / `ludicc`+`ludic` +> binaries) via serialized reseeds of `selfhost/ludicc.seed.ll`; Phase 1 rode in +> alongside their `emit_*`/`main.ludic` work, combined suite **14/14 green**. + +--- + +## Why (the findings) + +Verified against the self-hosted compiler ([selfhost/parse.ludic](selfhost/parse.ludic), +[selfhost/parse_game.ludic](selfhost/parse_game.ludic), [selfhost/lex.ludic](selfhost/lex.ludic)): + +**Structural incoherence** +1. **Five micro-syntaxes for named parts** — `name: type = d` (fields), `name: type` + (params), `Field = { k = v }` (spawn), `[Name, {Tag}]` (query), whitespace + `phase X reads [..]` (system clauses), `key=value` (ui props). +2. **`=` means seven things, `:` means one** — assignment, default, record init, + ui prop, extern symbol, const value, `state X = N` all use `=`. +3. **No statement terminators** — `\n` and `;` both lex to `TK_NL` + ([lex.ludic:45,121](selfhost/lex.ludic)) but the parser never requires a + separator, so `t.kind = k t.text = x t.ival = v` (three statements, spaces + only) is idiomatic. + +**Broken / dead syntax (compiler-verified)** +4. `edge system` — **hard parse error** (documented at [LANGUAGE.md:188](LANGUAGE.md)). *(✅ fixed in Phase 1)* +5. `pure fn` — parses, `pure` silently discarded ([parse.ludic:272](selfhost/parse.ludic)); undocumented. +6. `@anno` + `reads/writes/needs/uses [..]` — parsed then thrown away + ([parse_game.ludic:15-31](selfhost/parse_game.ludic)); four synonyms, two undocumented. +7. `scene`/`layer`/`on enter` — full LANGUAGE.md section + [examples/scenes.ludic](examples/scenes.ludic), + **does not compile** (`expected declaration`). +8. `query (v) [..]` in a system signature — two LANGUAGE.md sections + + [examples/qdecl.ludic](examples/qdecl.ludic), **does not compile** (`parse error: {`). *(✅ implemented in Phase 1)* +9. `when cond {}` — documented ([LANGUAGE.md:329](LANGUAGE.md)) + in all three editor + highlighters, **never parsed**. *(✅ implemented in Phase 1 as an if-without-else alias)* +10. CLI `--emit-llvm`/`-o`/`--shared`/`--fmt` — documented, but `ludicc` only + accepts `--windowed`/`--headless` ([main.ludic:8-14](selfhost/main.ludic)). + +**Philosophical splits** +11. Operators are words (`and`/`or`/`not`), symbols (`==`/`<=`), *and* functions + (`band`/`shl`) at once. +12. Three overlapping control families — `if`/`when`, `match`, `machine`/`become` + — and `enter` reuses `become`'s AST node ([parse.ludic:176-177](selfhost/parse.ludic)). +13. Typed components/structs exist, but real state lives in 64 untyped int + registers (`reg`/`setreg`), so `machine`/`match` dispatch on magic numbers. + +--- + +## The two rules everything converges on + +**Rule A — `:` associates, `=` binds.** +- `:` introduces a *named part* and its type or value in a declarative structure: + component/struct fields' types, record initializers, ui props, (future) named + call arguments. +- `=` binds a value to a storage location or a constant: `let`, assignment + (`+=` …), `const` value, a field's **default**, and the extern symbol. +- A field declaration uses both, unambiguously: `x: int = 0` reads "`x` *has type* + `int` (`:`), *defaulting to* `0` (`=`)" — same shape as Rust/TypeScript. +- A record/spawn initializer is declarative, so it uses `:` — `Pos { x: 10 }`. + +**Rule B — a statement ends at a newline (or `;` or `}`).** +- Newlines become significant. Two statements on one line require an explicit + `;`. `ludic-fmt` normalizes one statement per line and inserts/removes `;`. + +Everything below is these two rules applied construct by construct. + +--- + +## Target grammar (before → after) + +### Records / spawn initializers +```ludic +# doc-check: skip — illustrative redesign snippet (proposed / partial syntax) +# before +spawn Hero { Pos = { x = 10, y = 5 } Player = { } } +# after +spawn Hero { + Pos { x: 10, y: 5 } + Player {} +} +``` +`Field = { k = v }` → `Field { k: v }`. The component name is followed directly +by a record; fields use `:`. (Record literals elsewhere read the same: +`{ x: 10, y: 5 }`.) + +### UI props → named-argument form +```ludic +# doc-check: skip — illustrative redesign snippet (proposed / partial syntax) +# before +panel id=Root w=288 pad=16 gap=6 align=center { label text="HI" size=26 } +# after +panel(id: Root, w: 288, pad: 16, gap: 6, align: center) { + label(text: "HI", size: 26) +} +``` +A widget becomes "a constructor with named args, then an optional child block." +This deletes the bespoke `key=value` dialect and reuses `:` + commas. (Lower-churn +alternative if the paren form is disliked: keep whitespace separation but colonize +— `panel id: Root w: 288` — still removes the `=` overload.) + +### System clauses & modifiers → one annotation channel +```ludic +# doc-check: skip — illustrative redesign snippet (proposed / partial syntax) +# before +edge system Move @deterministic reads [Vel] writes [Pos] phase FixedUpdate + query (p, v) [Pos, Vel] where a.x > 0 { … } +# after +@edge @deterministic +system Move + phase FixedUpdate + reads [Vel] writes [Pos] + query (p, v) [Pos, Vel] where p.x > 0 +{ … } +``` +- Prefix modifier words (`edge`, `pure`, `export`) are **retired**; all modifiers + become `@annotations`, parsed into a real list on the node (not skipped). This + fixes the `edge system` parse bug (#4) by construction. +- `needs`/`uses` are dropped; `reads`/`writes` stay as the two structural clauses + and are **stored** (even if analysis is future work) rather than discarded. +- The `query (v) [..]` signature clause is **actually implemented** in + `parse_system` (#8), lowering to the same `S_QUERY` node as the inline `for`. + +### extern +```ludic +# doc-check: skip — illustrative redesign snippet (proposed / partial syntax) +extern fn c_hypot(a: fixed, b: fixed) -> fixed = "hypot_fx" # unchanged +``` +The `= "symbol"` is a binding under Rule A — it stays. + +### Statements +```ludic +# doc-check: skip — illustrative redesign snippet (proposed / partial syntax) +# before (legal today) +t.kind = kind t.text = text t.ival = ival +# after +t.kind = kind +t.text = text +t.ival = ival +# or, explicitly, on one line: +t.kind = kind; t.text = text; t.ival = ival +``` + +### Control flow (Phase 4) +- **`when` vs `if`** — `when` is now a working `if`-without-else alias (Phase 1). + Phase 4 decides whether to keep both spellings or collapse to one; if collapsed, + remove `when` from docs, the parser, and all editor highlighters together. +- **Typed states replace magic-int machines.** Introduce `enum`, and let + `machine` dispatch on a typed variable instead of a register: +```ludic +# doc-check: skip — illustrative redesign snippet (proposed / partial syntax) +# before # after +const R_PHASE: int = 0 enum Phase { KnightMenu, KnightResolve, MageMenu, EnemyTurn } +machine R_PHASE { var phase: Phase = Phase.KnightMenu + state KnightMenu = 0 { … become … } machine phase { + state KnightResolve = 1 { … } state KnightMenu { … become KnightResolve } +} state KnightResolve { … } + } +``` + `state X = N` loses the magic `= N` (ordinal comes from the enum). `become` + and `enter` (scenes) keep one shared lowering but read from a typed slot. + +--- + +## Phase sequence + +Each phase is independently shippable and ends green on `./test.sh` + +`./selfhost/test.sh` (fixpoint). + +### Phase 0 — Doctrine (done here) +Rules A and B above; colon-everywhere; `@`-annotations as the single modifier +channel; typed enums for state. No code. + +### Phase 1 — Truth-in-documentation ✅ DONE +Made spec ⇄ compiler agree **before** any grammar change. What landed: +- ✅ **`edge system` crash fixed** (#4) — `parse_system` now consumes an optional + `edge` marker before `system` ([parse_game.ludic](selfhost/parse_game.ludic)). + (`edge` is a pure marker; the emitter never lowered it differently.) +- ✅ **Signature-`query` implemented** (#8) — `query (vars) [terms] where c` in a + system header desugars to the same `S_QUERY` node the inline `for` builds, so + `examples/qdecl.ludic` compiles and runs. Also fixed multi-line clause parsing + (clauses may now span lines). +- ✅ **`when c { }` implemented** (#9) — as an `if`-without-else alias in + [parse.ludic](selfhost/parse.ludic). Docs + editors already listed it; now the + compiler agrees, so no editor-vocab churn was needed. +- ✅ **`scene`/`layer` marked not-yet-implemented** (#7) — prominent note in + LANGUAGE.md §"Scenes & layers" + a header on [examples/scenes.ludic](examples/scenes.ludic). + Full scene front-end + emission deferred (real work, out of Phase 1 scope). +- ✅ **`reads`/`writes` honesty** (#6) + the stale "Not yet implemented" section + updated in [LANGUAGE.md](LANGUAGE.md); scenes/reads-writes/dropped-CLI-flags now + listed there. +- ✅ **`test.sh` guards drift** — added a `qsmoke qdecl` compile check. Suite + green (14/14 incl. the toolchain agent's CLI smoke tests). +- ✅ **CLI flags** (#10) — `--shared`/`--fmt`/wasm noted as dropped-with-the-C-driver + in LANGUAGE.md; `-o`/`--emit-llvm` were being re-added by the toolchain agent + (now real, verified in `test.sh`); COMPILING.md updated by that agent. +- Deferred (intentionally): `pure`-is-ignored (#5) is undocumented and harmless; + it will be folded into `@pure` in Phase 3 rather than churned now. +- **Not done / by design:** `scenes.ludic` is *not* added to `test.sh` (it can't + compile yet — a positive test would fail; the header note + LANGUAGE.md warning + cover the drift instead). + +### Phase 2 — Statement separation (Rule B) +- Enforce a separator in `block()`/`stmt()` ([parse.ludic:130-199](selfhost/parse.ludic)): + after a statement, require `TK_NL` or `}`. +- Teach `ludic-fmt` to normalize one-statement-per-line and insert `;` where two + share a line. Reformat the whole corpus with it. +- Risk: the self-host sources themselves use space-juxtaposed statements heavily + — reformat them in the same commit, re-seed, re-verify fixpoint. + +### Phase 3 — Named-field unification (Rule A) +- Migrate spawn/record init (`= {…=…}` → `{…:…}`) and ui props (`key=value` → + named-arg form) in the parser and emitters. +- Collapse `reads/writes/needs/uses` → `reads`/`writes`, stored on the node. +- Move `edge`/`pure`/`export` into `@`-annotations; parse annotations into a list. +- Ship `ludic-fmt --migrate`: a mechanical codemod that rewrites old syntax to + new, run over `examples/`, `runtime/`, and `selfhost/`. +- Gate: compiler still self-hosts; every golden render is byte-identical. + +### Phase 4 — Control-flow & operator consolidation (largest) +- Remove `when`; confirm `if` covers all uses in the corpus. +- Introduce `enum` + typed `machine`/state; migrate `combat.ludic`'s R_PHASE + machine and the register-driven `match reg(…)` sites. +- Decide the bitwise story: keep `band/shl/…` as functions (document as a + deliberate "one spelling" choice) or promote to operators — pick one and state + it, don't leave it implicit. + +### Phase 5 — Single source of truth for keywords/grammar +- Generate every editor plugin keyword list, `ludic_syntax.h`, and the LSP's + token set from **one** canonical list so a keyword can never again be + highlighted but unparsed. +- Add a CI check (extend `tools/check-docs.py` / `check-vocabulary.py`) that + every ` ```ludic ` fence in the docs compiles, closing the doc-drift loop + permanently. + +--- + +## Decision log +- **Scope:** full redesign, Phases 0–5. *(chosen)* +- **Named fields:** colon everywhere; `=` is binding-only. *(chosen)* +- **Open — Phase 4 detail:** typed `enum` state vs. keep integer registers. + Recommended: typed enums (fixes #13), but it's the deepest change; can be + deferred without blocking Phases 1–3. +- **Open — ui props:** paren named-args (`panel(id: Root)`) vs. colonized + whitespace (`panel id: Root`). Recommended: paren form for full cohesion. +- **Open — bitwise ops:** functions (status quo, documented) vs. operators. diff --git a/assets/kenney/tiny-dungeon/License.txt b/assets/kenney/tiny-dungeon/License.txt new file mode 100644 index 00000000..1b269f6a --- /dev/null +++ b/assets/kenney/tiny-dungeon/License.txt @@ -0,0 +1,22 @@ + + + Tiny Dungeon (1.0) + + Created/distributed by Kenney (www.kenney.nl) + Creation date: 05-07-2022 + + ------------------------------ + + License: (Creative Commons Zero, CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + This content is free to use in personal, educational and commercial projects. + Support us by crediting Kenney or www.kenney.nl (this is not mandatory) + + ------------------------------ + + Donate: http://support.kenney.nl + Patreon: http://patreon.com/kenney/ + + Follow on Twitter for updates: + http://twitter.com/KenneyNL \ No newline at end of file diff --git a/assets/kenney/tiny-dungeon/Preview.png b/assets/kenney/tiny-dungeon/Preview.png new file mode 100644 index 00000000..01c23ad3 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Preview.png differ diff --git a/assets/kenney/tiny-dungeon/Sample.png b/assets/kenney/tiny-dungeon/Sample.png new file mode 100644 index 00000000..505a6d64 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Sample.png differ diff --git a/assets/kenney/tiny-dungeon/Tiled/sampleMap.tmx b/assets/kenney/tiny-dungeon/Tiled/sampleMap.tmx new file mode 100644 index 00000000..9227705a --- /dev/null +++ b/assets/kenney/tiny-dungeon/Tiled/sampleMap.tmx @@ -0,0 +1,76 @@ + + + + + +14,1610612787,16,1,1,3221225485,1,1,1,2,3,3,3,3,3,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +14,1610612787,17,3,3,4,1,1,1,14,41,41,41,41,41,16,1,1,1,1,1,25,1,1,1,1,1,1,1,1,1073741837,1, +14,1610612787,58,41,41,16,25,1,1,14,1610612789,51,51,52,51,16,2,3,4,1,1,1,1,2,3,7,3,3,3,7,3,4, +14,1610612787,51,52,51,16,1,1,1,14,1610612787,49,3221225522,49,49,16,14,41,16,1,1,536870925,1,14,41,19,41,30,41,19,41,16, +14,1610612787,5,27,27,28,1,1073741837,1,14,1610612787,49,49,49,49,16,14,1610612789,16,1,1,1,1073741837,14,1610612789,31,51,51,52,31,51,16, +14,1610612787,16,2,3,3,3,3,4,26,27,27,27,27,27,28,14,1610612787,17,7,3,3,4,14,1610612787,49,49,49,49,49,49,16, +14,1610612787,16,14,41,41,41,41,17,3,3,3,3,4,1,1,14,1610612787,58,19,41,41,16,14,1610612787,49,49,49,49,49,49,16, +18,1610612787,17,18,1610612789,51,52,51,58,41,41,22,41,16,2684354573,1,14,1610612787,51,31,51,51,16,14,1610612787,49,49,49,49,49,49,16, +60,1610612787,58,60,1610612787,49,49,49,51,51,51,51,51,17,3,3,18,1610612787,49,43,49,3221225522,17,18,1610612787,49,49,49,49,49,2684354610,17, +51,54,51,51,54,43,49,50,49,49,49,49,49,58,41,41,60,1610612787,49,49,43,49,58,60,37,38,38,38,38,38,39,58, +49,43,49,49,49,49,49,49,49,49,49,49,49,51,52,51,51,54,49,49,49,49,51,52,54,49,49,49,49,49,49,51, +49,49,49,5,27,6,1610612790,49,49,2147483698,49,49,49,49,49,49,49,49,49,49,49,49,49,5,27,27,27,27,27,27,27,27, +49,49,49,16,1,14,1610612787,49,49,49,49,49,49,5,27,27,27,27,27,27,6,1610612790,49,16,1,1,1,1,1,1,1,1, +27,27,27,28,3221225485,14,1610612787,49,49,5,27,27,27,28,2,3,3,3,3,3,18,1610612787,49,16,1,1,1,2,3,3,3,3, +1,1,1,1,2,18,1610612787,49,49,17,3,4,1,1,14,41,20,41,41,21,60,1610612787,49,16,1,1,1073741837,14,41,11,12,41, +1,2,3,3,18,60,1610612787,49,49,58,41,17,3,3,18,1610612789,32,51,51,33,51,54,2147483698,16,1,1,1,14,1610612789,51,51,51, +1,14,41,41,60,1610612789,54,49,49,51,51,58,41,41,60,1610612787,49,43,49,49,49,49,49,17,3,3,3,18,1610612787,49,49,49, +1,14,1610612789,52,51,54,49,49,2147483698,42,49,51,51,51,51,54,43,49,49,49,49,49,49,58,41,41,41,60,1610612787,49,49,49, +1,14,1610612787,3758096434,49,49,49,49,49,3758096434,49,49,49,49,49,49,49,49,49,49,49,43,49,51,51,51,51,51,54,49,49,49, +1,14,1610612787,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,3758096434,49 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,87,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,0,65,0,65,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,0,67,0,67,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,121,0,0,0,0,0,0, +0,0,0,0,0,112,0,0,0,62,0,0,0,0,0,0,0,0,74,0,73,0,0,0,0,0,121,0,0,0,0,0, +0,0,65,0,0,0,0,0,62,88,62,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0, +0,0,67,0,0,0,0,0,98,62,0,0,0,0,0,85,0,0,0,2147483758,0,0,0,0,0,0,0,0,0,0,0,0, +0,65,0,0,0,0,0,0,0,0,99,61,0,0,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,0,0,0, +0,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0,0,0,78,78,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,83, +0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,90,0,0, +0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,2147483773,0,0,0,0,0,0,0,0,2147483749,0, +0,0,0,0,0,0,0,94,71,71,71,71,71,72,0,0,0,0,0,0,0,0,0,0,0,0,83,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,55,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/assets/kenney/tiny-dungeon/Tiled/sampleSheet.tsx b/assets/kenney/tiny-dungeon/Tiled/sampleSheet.tsx new file mode 100644 index 00000000..46a615e4 --- /dev/null +++ b/assets/kenney/tiny-dungeon/Tiled/sampleSheet.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/assets/kenney/tiny-dungeon/Tilemap/tilemap.png b/assets/kenney/tiny-dungeon/Tilemap/tilemap.png new file mode 100644 index 00000000..a893ccb0 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tilemap/tilemap.png differ diff --git a/assets/kenney/tiny-dungeon/Tilemap/tilemap_packed.png b/assets/kenney/tiny-dungeon/Tilemap/tilemap_packed.png new file mode 100644 index 00000000..f6e8b937 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tilemap/tilemap_packed.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0000.png b/assets/kenney/tiny-dungeon/Tiles/tile_0000.png new file mode 100644 index 00000000..6bd64a79 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0000.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0001.png b/assets/kenney/tiny-dungeon/Tiles/tile_0001.png new file mode 100644 index 00000000..cdaffc09 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0001.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0002.png b/assets/kenney/tiny-dungeon/Tiles/tile_0002.png new file mode 100644 index 00000000..0b4f047b Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0002.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0003.png b/assets/kenney/tiny-dungeon/Tiles/tile_0003.png new file mode 100644 index 00000000..c03b478f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0003.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0004.png b/assets/kenney/tiny-dungeon/Tiles/tile_0004.png new file mode 100644 index 00000000..e55ab28b Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0004.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0005.png b/assets/kenney/tiny-dungeon/Tiles/tile_0005.png new file mode 100644 index 00000000..e4d148bf Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0005.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0006.png b/assets/kenney/tiny-dungeon/Tiles/tile_0006.png new file mode 100644 index 00000000..fe7f7b35 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0006.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0007.png b/assets/kenney/tiny-dungeon/Tiles/tile_0007.png new file mode 100644 index 00000000..029bf8c9 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0007.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0008.png b/assets/kenney/tiny-dungeon/Tiles/tile_0008.png new file mode 100644 index 00000000..0ee6237e Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0008.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0009.png b/assets/kenney/tiny-dungeon/Tiles/tile_0009.png new file mode 100644 index 00000000..3a47228d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0009.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0010.png b/assets/kenney/tiny-dungeon/Tiles/tile_0010.png new file mode 100644 index 00000000..3e7352b0 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0010.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0011.png b/assets/kenney/tiny-dungeon/Tiles/tile_0011.png new file mode 100644 index 00000000..2ceaed8d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0011.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0012.png b/assets/kenney/tiny-dungeon/Tiles/tile_0012.png new file mode 100644 index 00000000..4320cb2f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0012.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0013.png b/assets/kenney/tiny-dungeon/Tiles/tile_0013.png new file mode 100644 index 00000000..3a5b250c Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0013.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0014.png b/assets/kenney/tiny-dungeon/Tiles/tile_0014.png new file mode 100644 index 00000000..bec979d9 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0014.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0015.png b/assets/kenney/tiny-dungeon/Tiles/tile_0015.png new file mode 100644 index 00000000..32e03a9d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0015.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0016.png b/assets/kenney/tiny-dungeon/Tiles/tile_0016.png new file mode 100644 index 00000000..12634df1 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0016.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0017.png b/assets/kenney/tiny-dungeon/Tiles/tile_0017.png new file mode 100644 index 00000000..148bc277 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0017.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0018.png b/assets/kenney/tiny-dungeon/Tiles/tile_0018.png new file mode 100644 index 00000000..10d95da8 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0018.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0019.png b/assets/kenney/tiny-dungeon/Tiles/tile_0019.png new file mode 100644 index 00000000..8c1285f1 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0019.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0020.png b/assets/kenney/tiny-dungeon/Tiles/tile_0020.png new file mode 100644 index 00000000..6dfd70ed Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0020.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0021.png b/assets/kenney/tiny-dungeon/Tiles/tile_0021.png new file mode 100644 index 00000000..e7d18500 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0021.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0022.png b/assets/kenney/tiny-dungeon/Tiles/tile_0022.png new file mode 100644 index 00000000..4e9bc129 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0022.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0023.png b/assets/kenney/tiny-dungeon/Tiles/tile_0023.png new file mode 100644 index 00000000..07921a67 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0023.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0024.png b/assets/kenney/tiny-dungeon/Tiles/tile_0024.png new file mode 100644 index 00000000..ec6d9038 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0024.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0025.png b/assets/kenney/tiny-dungeon/Tiles/tile_0025.png new file mode 100644 index 00000000..da5f19ab Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0025.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0026.png b/assets/kenney/tiny-dungeon/Tiles/tile_0026.png new file mode 100644 index 00000000..e93246af Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0026.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0027.png b/assets/kenney/tiny-dungeon/Tiles/tile_0027.png new file mode 100644 index 00000000..1ce15f4b Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0027.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0028.png b/assets/kenney/tiny-dungeon/Tiles/tile_0028.png new file mode 100644 index 00000000..bf1c3a2b Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0028.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0029.png b/assets/kenney/tiny-dungeon/Tiles/tile_0029.png new file mode 100644 index 00000000..7b0e33d5 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0029.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0030.png b/assets/kenney/tiny-dungeon/Tiles/tile_0030.png new file mode 100644 index 00000000..1b597ca6 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0030.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0031.png b/assets/kenney/tiny-dungeon/Tiles/tile_0031.png new file mode 100644 index 00000000..acd9203f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0031.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0032.png b/assets/kenney/tiny-dungeon/Tiles/tile_0032.png new file mode 100644 index 00000000..77ca1a73 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0032.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0033.png b/assets/kenney/tiny-dungeon/Tiles/tile_0033.png new file mode 100644 index 00000000..2cf8cb1d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0033.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0034.png b/assets/kenney/tiny-dungeon/Tiles/tile_0034.png new file mode 100644 index 00000000..98076aaa Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0034.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0035.png b/assets/kenney/tiny-dungeon/Tiles/tile_0035.png new file mode 100644 index 00000000..1e414988 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0035.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0036.png b/assets/kenney/tiny-dungeon/Tiles/tile_0036.png new file mode 100644 index 00000000..23c3a83a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0036.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0037.png b/assets/kenney/tiny-dungeon/Tiles/tile_0037.png new file mode 100644 index 00000000..1d2d9623 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0037.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0038.png b/assets/kenney/tiny-dungeon/Tiles/tile_0038.png new file mode 100644 index 00000000..96972bda Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0038.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0039.png b/assets/kenney/tiny-dungeon/Tiles/tile_0039.png new file mode 100644 index 00000000..75667caf Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0039.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0040.png b/assets/kenney/tiny-dungeon/Tiles/tile_0040.png new file mode 100644 index 00000000..1191cd30 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0040.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0041.png b/assets/kenney/tiny-dungeon/Tiles/tile_0041.png new file mode 100644 index 00000000..dbcdc56a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0041.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0042.png b/assets/kenney/tiny-dungeon/Tiles/tile_0042.png new file mode 100644 index 00000000..4ac7fa5d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0042.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0043.png b/assets/kenney/tiny-dungeon/Tiles/tile_0043.png new file mode 100644 index 00000000..f12545f1 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0043.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0044.png b/assets/kenney/tiny-dungeon/Tiles/tile_0044.png new file mode 100644 index 00000000..3d05e584 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0044.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0045.png b/assets/kenney/tiny-dungeon/Tiles/tile_0045.png new file mode 100644 index 00000000..22e16254 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0045.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0046.png b/assets/kenney/tiny-dungeon/Tiles/tile_0046.png new file mode 100644 index 00000000..1dc12130 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0046.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0047.png b/assets/kenney/tiny-dungeon/Tiles/tile_0047.png new file mode 100644 index 00000000..e9a7f9fe Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0047.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0048.png b/assets/kenney/tiny-dungeon/Tiles/tile_0048.png new file mode 100644 index 00000000..6e59a442 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0048.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0049.png b/assets/kenney/tiny-dungeon/Tiles/tile_0049.png new file mode 100644 index 00000000..c7d07222 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0049.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0050.png b/assets/kenney/tiny-dungeon/Tiles/tile_0050.png new file mode 100644 index 00000000..b4464f3f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0050.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0051.png b/assets/kenney/tiny-dungeon/Tiles/tile_0051.png new file mode 100644 index 00000000..7bc6fe4f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0051.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0052.png b/assets/kenney/tiny-dungeon/Tiles/tile_0052.png new file mode 100644 index 00000000..8a17adb9 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0052.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0053.png b/assets/kenney/tiny-dungeon/Tiles/tile_0053.png new file mode 100644 index 00000000..a8ac9940 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0053.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0054.png b/assets/kenney/tiny-dungeon/Tiles/tile_0054.png new file mode 100644 index 00000000..39b9cf6d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0054.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0055.png b/assets/kenney/tiny-dungeon/Tiles/tile_0055.png new file mode 100644 index 00000000..655077e7 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0055.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0056.png b/assets/kenney/tiny-dungeon/Tiles/tile_0056.png new file mode 100644 index 00000000..0dfcb215 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0056.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0057.png b/assets/kenney/tiny-dungeon/Tiles/tile_0057.png new file mode 100644 index 00000000..f9ad9b7a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0057.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0058.png b/assets/kenney/tiny-dungeon/Tiles/tile_0058.png new file mode 100644 index 00000000..e498583c Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0058.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0059.png b/assets/kenney/tiny-dungeon/Tiles/tile_0059.png new file mode 100644 index 00000000..f47e75b3 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0059.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0060.png b/assets/kenney/tiny-dungeon/Tiles/tile_0060.png new file mode 100644 index 00000000..ad4779c9 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0060.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0061.png b/assets/kenney/tiny-dungeon/Tiles/tile_0061.png new file mode 100644 index 00000000..308dc05c Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0061.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0062.png b/assets/kenney/tiny-dungeon/Tiles/tile_0062.png new file mode 100644 index 00000000..e6790627 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0062.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0063.png b/assets/kenney/tiny-dungeon/Tiles/tile_0063.png new file mode 100644 index 00000000..11b5cf71 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0063.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0064.png b/assets/kenney/tiny-dungeon/Tiles/tile_0064.png new file mode 100644 index 00000000..c574d11a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0064.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0065.png b/assets/kenney/tiny-dungeon/Tiles/tile_0065.png new file mode 100644 index 00000000..8dba4014 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0065.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0066.png b/assets/kenney/tiny-dungeon/Tiles/tile_0066.png new file mode 100644 index 00000000..f5ae1b68 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0066.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0067.png b/assets/kenney/tiny-dungeon/Tiles/tile_0067.png new file mode 100644 index 00000000..db9f646c Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0067.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0068.png b/assets/kenney/tiny-dungeon/Tiles/tile_0068.png new file mode 100644 index 00000000..a03571a2 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0068.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0069.png b/assets/kenney/tiny-dungeon/Tiles/tile_0069.png new file mode 100644 index 00000000..fceb76e2 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0069.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0070.png b/assets/kenney/tiny-dungeon/Tiles/tile_0070.png new file mode 100644 index 00000000..c77f8aed Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0070.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0071.png b/assets/kenney/tiny-dungeon/Tiles/tile_0071.png new file mode 100644 index 00000000..9624f3f0 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0071.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0072.png b/assets/kenney/tiny-dungeon/Tiles/tile_0072.png new file mode 100644 index 00000000..6ca51a37 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0072.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0073.png b/assets/kenney/tiny-dungeon/Tiles/tile_0073.png new file mode 100644 index 00000000..00ff065f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0073.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0074.png b/assets/kenney/tiny-dungeon/Tiles/tile_0074.png new file mode 100644 index 00000000..407e2d15 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0074.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0075.png b/assets/kenney/tiny-dungeon/Tiles/tile_0075.png new file mode 100644 index 00000000..4b91993e Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0075.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0076.png b/assets/kenney/tiny-dungeon/Tiles/tile_0076.png new file mode 100644 index 00000000..08f2649e Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0076.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0077.png b/assets/kenney/tiny-dungeon/Tiles/tile_0077.png new file mode 100644 index 00000000..4e670408 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0077.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0078.png b/assets/kenney/tiny-dungeon/Tiles/tile_0078.png new file mode 100644 index 00000000..c3952356 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0078.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0079.png b/assets/kenney/tiny-dungeon/Tiles/tile_0079.png new file mode 100644 index 00000000..765965a9 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0079.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0080.png b/assets/kenney/tiny-dungeon/Tiles/tile_0080.png new file mode 100644 index 00000000..3336418b Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0080.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0081.png b/assets/kenney/tiny-dungeon/Tiles/tile_0081.png new file mode 100644 index 00000000..19e40a9a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0081.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0082.png b/assets/kenney/tiny-dungeon/Tiles/tile_0082.png new file mode 100644 index 00000000..78f95bce Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0082.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0083.png b/assets/kenney/tiny-dungeon/Tiles/tile_0083.png new file mode 100644 index 00000000..19e40a9a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0083.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0084.png b/assets/kenney/tiny-dungeon/Tiles/tile_0084.png new file mode 100644 index 00000000..83aef729 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0084.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0085.png b/assets/kenney/tiny-dungeon/Tiles/tile_0085.png new file mode 100644 index 00000000..5f12f941 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0085.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0086.png b/assets/kenney/tiny-dungeon/Tiles/tile_0086.png new file mode 100644 index 00000000..0a1cb832 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0086.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0087.png b/assets/kenney/tiny-dungeon/Tiles/tile_0087.png new file mode 100644 index 00000000..1b476473 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0087.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0088.png b/assets/kenney/tiny-dungeon/Tiles/tile_0088.png new file mode 100644 index 00000000..94aa932d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0088.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0089.png b/assets/kenney/tiny-dungeon/Tiles/tile_0089.png new file mode 100644 index 00000000..d4624352 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0089.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0090.png b/assets/kenney/tiny-dungeon/Tiles/tile_0090.png new file mode 100644 index 00000000..008737e4 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0090.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0091.png b/assets/kenney/tiny-dungeon/Tiles/tile_0091.png new file mode 100644 index 00000000..2b322b94 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0091.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0092.png b/assets/kenney/tiny-dungeon/Tiles/tile_0092.png new file mode 100644 index 00000000..906f46bd Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0092.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0093.png b/assets/kenney/tiny-dungeon/Tiles/tile_0093.png new file mode 100644 index 00000000..4914e05d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0093.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0094.png b/assets/kenney/tiny-dungeon/Tiles/tile_0094.png new file mode 100644 index 00000000..c77f8aed Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0094.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0095.png b/assets/kenney/tiny-dungeon/Tiles/tile_0095.png new file mode 100644 index 00000000..95b220bd Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0095.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0096.png b/assets/kenney/tiny-dungeon/Tiles/tile_0096.png new file mode 100644 index 00000000..ed3029ba Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0096.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0097.png b/assets/kenney/tiny-dungeon/Tiles/tile_0097.png new file mode 100644 index 00000000..b0106b2d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0097.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0098.png b/assets/kenney/tiny-dungeon/Tiles/tile_0098.png new file mode 100644 index 00000000..33953716 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0098.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0099.png b/assets/kenney/tiny-dungeon/Tiles/tile_0099.png new file mode 100644 index 00000000..2278e3ae Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0099.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0100.png b/assets/kenney/tiny-dungeon/Tiles/tile_0100.png new file mode 100644 index 00000000..be9422cd Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0100.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0101.png b/assets/kenney/tiny-dungeon/Tiles/tile_0101.png new file mode 100644 index 00000000..48971500 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0101.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0102.png b/assets/kenney/tiny-dungeon/Tiles/tile_0102.png new file mode 100644 index 00000000..c9681ed7 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0102.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0103.png b/assets/kenney/tiny-dungeon/Tiles/tile_0103.png new file mode 100644 index 00000000..23f289dc Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0103.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0104.png b/assets/kenney/tiny-dungeon/Tiles/tile_0104.png new file mode 100644 index 00000000..bb7c7028 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0104.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0105.png b/assets/kenney/tiny-dungeon/Tiles/tile_0105.png new file mode 100644 index 00000000..b699b1b0 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0105.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0106.png b/assets/kenney/tiny-dungeon/Tiles/tile_0106.png new file mode 100644 index 00000000..905ebcb6 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0106.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0107.png b/assets/kenney/tiny-dungeon/Tiles/tile_0107.png new file mode 100644 index 00000000..86517222 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0107.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0108.png b/assets/kenney/tiny-dungeon/Tiles/tile_0108.png new file mode 100644 index 00000000..7b6f8efd Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0108.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0109.png b/assets/kenney/tiny-dungeon/Tiles/tile_0109.png new file mode 100644 index 00000000..705fa2d3 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0109.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0110.png b/assets/kenney/tiny-dungeon/Tiles/tile_0110.png new file mode 100644 index 00000000..93866d10 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0110.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0111.png b/assets/kenney/tiny-dungeon/Tiles/tile_0111.png new file mode 100644 index 00000000..564b39cc Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0111.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0112.png b/assets/kenney/tiny-dungeon/Tiles/tile_0112.png new file mode 100644 index 00000000..6026b281 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0112.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0113.png b/assets/kenney/tiny-dungeon/Tiles/tile_0113.png new file mode 100644 index 00000000..0d070f9d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0113.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0114.png b/assets/kenney/tiny-dungeon/Tiles/tile_0114.png new file mode 100644 index 00000000..54e4df45 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0114.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0115.png b/assets/kenney/tiny-dungeon/Tiles/tile_0115.png new file mode 100644 index 00000000..00e3e0de Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0115.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0116.png b/assets/kenney/tiny-dungeon/Tiles/tile_0116.png new file mode 100644 index 00000000..caae164e Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0116.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0117.png b/assets/kenney/tiny-dungeon/Tiles/tile_0117.png new file mode 100644 index 00000000..eaea357b Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0117.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0118.png b/assets/kenney/tiny-dungeon/Tiles/tile_0118.png new file mode 100644 index 00000000..68ab0431 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0118.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0119.png b/assets/kenney/tiny-dungeon/Tiles/tile_0119.png new file mode 100644 index 00000000..98f10936 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0119.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0120.png b/assets/kenney/tiny-dungeon/Tiles/tile_0120.png new file mode 100644 index 00000000..2f0d9b14 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0120.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0121.png b/assets/kenney/tiny-dungeon/Tiles/tile_0121.png new file mode 100644 index 00000000..fca32b86 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0121.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0122.png b/assets/kenney/tiny-dungeon/Tiles/tile_0122.png new file mode 100644 index 00000000..179f42fd Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0122.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0123.png b/assets/kenney/tiny-dungeon/Tiles/tile_0123.png new file mode 100644 index 00000000..be4b83e8 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0123.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0124.png b/assets/kenney/tiny-dungeon/Tiles/tile_0124.png new file mode 100644 index 00000000..3fe67e4f Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0124.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0125.png b/assets/kenney/tiny-dungeon/Tiles/tile_0125.png new file mode 100644 index 00000000..3029b204 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0125.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0126.png b/assets/kenney/tiny-dungeon/Tiles/tile_0126.png new file mode 100644 index 00000000..d28ba06e Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0126.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0127.png b/assets/kenney/tiny-dungeon/Tiles/tile_0127.png new file mode 100644 index 00000000..20e0cc9d Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0127.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0128.png b/assets/kenney/tiny-dungeon/Tiles/tile_0128.png new file mode 100644 index 00000000..208da4d3 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0128.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0129.png b/assets/kenney/tiny-dungeon/Tiles/tile_0129.png new file mode 100644 index 00000000..ac7fe54a Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0129.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0130.png b/assets/kenney/tiny-dungeon/Tiles/tile_0130.png new file mode 100644 index 00000000..2cf4d02c Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0130.png differ diff --git a/assets/kenney/tiny-dungeon/Tiles/tile_0131.png b/assets/kenney/tiny-dungeon/Tiles/tile_0131.png new file mode 100644 index 00000000..ca4935b1 Binary files /dev/null and b/assets/kenney/tiny-dungeon/Tiles/tile_0131.png differ diff --git a/assets/kenney/tiny-dungeon/Tilesheet.txt b/assets/kenney/tiny-dungeon/Tilesheet.txt new file mode 100644 index 00000000..3ecbdd2a --- /dev/null +++ b/assets/kenney/tiny-dungeon/Tilesheet.txt @@ -0,0 +1,9 @@ +Tilesheet information: + +Tile size • 16px × 16px +Space between tiles • 1px × 1px +--- +Total tiles (horizontal) • 12 tiles +Total tiles (vertical) • 11 tiles +--- +Total tiles in sheet • 132 tiles \ No newline at end of file diff --git a/assets/kenney/tiny-dungeon/Visit Kenney.url b/assets/kenney/tiny-dungeon/Visit Kenney.url new file mode 100644 index 00000000..c220c41b --- /dev/null +++ b/assets/kenney/tiny-dungeon/Visit Kenney.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=http://www.kenney.nl/ \ No newline at end of file diff --git a/assets/kenney/tiny-dungeon/Visit Patreon.url b/assets/kenney/tiny-dungeon/Visit Patreon.url new file mode 100644 index 00000000..67e9ea57 --- /dev/null +++ b/assets/kenney/tiny-dungeon/Visit Patreon.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://www.patreon.com/kenney/ \ No newline at end of file diff --git a/assets/kenney/tiny-town/License.txt b/assets/kenney/tiny-town/License.txt new file mode 100644 index 00000000..21ea3729 --- /dev/null +++ b/assets/kenney/tiny-town/License.txt @@ -0,0 +1,22 @@ + + + Tiny Town (1.1) + + Created/distributed by Kenney (www.kenney.nl) + Creation date: 11-01-2023 + + ------------------------------ + + License: (Creative Commons Zero, CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + This content is free to use in personal, educational and commercial projects. + Support us by crediting Kenney or www.kenney.nl (this is not mandatory) + + ------------------------------ + + Donate: http://support.kenney.nl + Patreon: http://patreon.com/kenney/ + + Follow on Twitter for updates: + http://twitter.com/KenneyNL \ No newline at end of file diff --git a/assets/kenney/tiny-town/Preview.png b/assets/kenney/tiny-town/Preview.png new file mode 100644 index 00000000..127e13ce Binary files /dev/null and b/assets/kenney/tiny-town/Preview.png differ diff --git a/assets/kenney/tiny-town/Sample.png b/assets/kenney/tiny-town/Sample.png new file mode 100644 index 00000000..10e4a71b Binary files /dev/null and b/assets/kenney/tiny-town/Sample.png differ diff --git a/assets/kenney/tiny-town/Tilemap/tilemap.png b/assets/kenney/tiny-town/Tilemap/tilemap.png new file mode 100644 index 00000000..21b5a0f8 Binary files /dev/null and b/assets/kenney/tiny-town/Tilemap/tilemap.png differ diff --git a/assets/kenney/tiny-town/Tilemap/tilemap_packed.png b/assets/kenney/tiny-town/Tilemap/tilemap_packed.png new file mode 100644 index 00000000..1655d1df Binary files /dev/null and b/assets/kenney/tiny-town/Tilemap/tilemap_packed.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0000.png b/assets/kenney/tiny-town/Tiles/tile_0000.png new file mode 100644 index 00000000..e743c542 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0000.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0001.png b/assets/kenney/tiny-town/Tiles/tile_0001.png new file mode 100644 index 00000000..9f8471ab Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0001.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0002.png b/assets/kenney/tiny-town/Tiles/tile_0002.png new file mode 100644 index 00000000..8f24c62e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0002.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0003.png b/assets/kenney/tiny-town/Tiles/tile_0003.png new file mode 100644 index 00000000..2caf2103 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0003.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0004.png b/assets/kenney/tiny-town/Tiles/tile_0004.png new file mode 100644 index 00000000..4bbe8cd5 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0004.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0005.png b/assets/kenney/tiny-town/Tiles/tile_0005.png new file mode 100644 index 00000000..f5354956 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0005.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0006.png b/assets/kenney/tiny-town/Tiles/tile_0006.png new file mode 100644 index 00000000..20f607bd Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0006.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0007.png b/assets/kenney/tiny-town/Tiles/tile_0007.png new file mode 100644 index 00000000..f1cab07c Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0007.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0008.png b/assets/kenney/tiny-town/Tiles/tile_0008.png new file mode 100644 index 00000000..037cef7b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0008.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0009.png b/assets/kenney/tiny-town/Tiles/tile_0009.png new file mode 100644 index 00000000..ce63263b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0009.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0010.png b/assets/kenney/tiny-town/Tiles/tile_0010.png new file mode 100644 index 00000000..1aa04494 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0010.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0011.png b/assets/kenney/tiny-town/Tiles/tile_0011.png new file mode 100644 index 00000000..b1b78423 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0011.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0012.png b/assets/kenney/tiny-town/Tiles/tile_0012.png new file mode 100644 index 00000000..c664900e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0012.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0013.png b/assets/kenney/tiny-town/Tiles/tile_0013.png new file mode 100644 index 00000000..47bec789 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0013.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0014.png b/assets/kenney/tiny-town/Tiles/tile_0014.png new file mode 100644 index 00000000..20737fce Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0014.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0015.png b/assets/kenney/tiny-town/Tiles/tile_0015.png new file mode 100644 index 00000000..d6302ed3 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0015.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0016.png b/assets/kenney/tiny-town/Tiles/tile_0016.png new file mode 100644 index 00000000..bafb634e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0016.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0017.png b/assets/kenney/tiny-town/Tiles/tile_0017.png new file mode 100644 index 00000000..4889f5b4 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0017.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0018.png b/assets/kenney/tiny-town/Tiles/tile_0018.png new file mode 100644 index 00000000..f9f97f85 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0018.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0019.png b/assets/kenney/tiny-town/Tiles/tile_0019.png new file mode 100644 index 00000000..edcb1c14 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0019.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0020.png b/assets/kenney/tiny-town/Tiles/tile_0020.png new file mode 100644 index 00000000..33d86905 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0020.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0021.png b/assets/kenney/tiny-town/Tiles/tile_0021.png new file mode 100644 index 00000000..f39998d9 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0021.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0022.png b/assets/kenney/tiny-town/Tiles/tile_0022.png new file mode 100644 index 00000000..e7e722a0 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0022.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0023.png b/assets/kenney/tiny-town/Tiles/tile_0023.png new file mode 100644 index 00000000..14ba8d16 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0023.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0024.png b/assets/kenney/tiny-town/Tiles/tile_0024.png new file mode 100644 index 00000000..7fec97cb Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0024.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0025.png b/assets/kenney/tiny-town/Tiles/tile_0025.png new file mode 100644 index 00000000..6e59a442 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0025.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0026.png b/assets/kenney/tiny-town/Tiles/tile_0026.png new file mode 100644 index 00000000..36b21a01 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0026.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0027.png b/assets/kenney/tiny-town/Tiles/tile_0027.png new file mode 100644 index 00000000..53ce6005 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0027.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0028.png b/assets/kenney/tiny-town/Tiles/tile_0028.png new file mode 100644 index 00000000..ccce87ca Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0028.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0029.png b/assets/kenney/tiny-town/Tiles/tile_0029.png new file mode 100644 index 00000000..44735ba5 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0029.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0030.png b/assets/kenney/tiny-town/Tiles/tile_0030.png new file mode 100644 index 00000000..03956c6a Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0030.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0031.png b/assets/kenney/tiny-town/Tiles/tile_0031.png new file mode 100644 index 00000000..f857d721 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0031.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0032.png b/assets/kenney/tiny-town/Tiles/tile_0032.png new file mode 100644 index 00000000..a3b45637 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0032.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0033.png b/assets/kenney/tiny-town/Tiles/tile_0033.png new file mode 100644 index 00000000..19423730 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0033.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0034.png b/assets/kenney/tiny-town/Tiles/tile_0034.png new file mode 100644 index 00000000..36aba0cf Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0034.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0035.png b/assets/kenney/tiny-town/Tiles/tile_0035.png new file mode 100644 index 00000000..391b766d Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0035.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0036.png b/assets/kenney/tiny-town/Tiles/tile_0036.png new file mode 100644 index 00000000..483b603f Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0036.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0037.png b/assets/kenney/tiny-town/Tiles/tile_0037.png new file mode 100644 index 00000000..ffa75785 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0037.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0038.png b/assets/kenney/tiny-town/Tiles/tile_0038.png new file mode 100644 index 00000000..8b786b64 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0038.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0039.png b/assets/kenney/tiny-town/Tiles/tile_0039.png new file mode 100644 index 00000000..ba565dae Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0039.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0040.png b/assets/kenney/tiny-town/Tiles/tile_0040.png new file mode 100644 index 00000000..92284af1 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0040.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0041.png b/assets/kenney/tiny-town/Tiles/tile_0041.png new file mode 100644 index 00000000..f57be423 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0041.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0042.png b/assets/kenney/tiny-town/Tiles/tile_0042.png new file mode 100644 index 00000000..4e06403d Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0042.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0043.png b/assets/kenney/tiny-town/Tiles/tile_0043.png new file mode 100644 index 00000000..cf9b5629 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0043.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0044.png b/assets/kenney/tiny-town/Tiles/tile_0044.png new file mode 100644 index 00000000..4a0799d3 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0044.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0045.png b/assets/kenney/tiny-town/Tiles/tile_0045.png new file mode 100644 index 00000000..11e15911 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0045.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0046.png b/assets/kenney/tiny-town/Tiles/tile_0046.png new file mode 100644 index 00000000..1ff37186 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0046.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0047.png b/assets/kenney/tiny-town/Tiles/tile_0047.png new file mode 100644 index 00000000..154f3fa2 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0047.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0048.png b/assets/kenney/tiny-town/Tiles/tile_0048.png new file mode 100644 index 00000000..3d500133 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0048.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0049.png b/assets/kenney/tiny-town/Tiles/tile_0049.png new file mode 100644 index 00000000..fbe1d9f7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0049.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0050.png b/assets/kenney/tiny-town/Tiles/tile_0050.png new file mode 100644 index 00000000..c17255ca Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0050.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0051.png b/assets/kenney/tiny-town/Tiles/tile_0051.png new file mode 100644 index 00000000..d9f64fd8 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0051.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0052.png b/assets/kenney/tiny-town/Tiles/tile_0052.png new file mode 100644 index 00000000..f94e72d7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0052.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0053.png b/assets/kenney/tiny-town/Tiles/tile_0053.png new file mode 100644 index 00000000..ce348879 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0053.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0054.png b/assets/kenney/tiny-town/Tiles/tile_0054.png new file mode 100644 index 00000000..d04ac27f Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0054.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0055.png b/assets/kenney/tiny-town/Tiles/tile_0055.png new file mode 100644 index 00000000..7fffe672 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0055.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0056.png b/assets/kenney/tiny-town/Tiles/tile_0056.png new file mode 100644 index 00000000..6873383e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0056.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0057.png b/assets/kenney/tiny-town/Tiles/tile_0057.png new file mode 100644 index 00000000..2b78dd61 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0057.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0058.png b/assets/kenney/tiny-town/Tiles/tile_0058.png new file mode 100644 index 00000000..a27b994d Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0058.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0059.png b/assets/kenney/tiny-town/Tiles/tile_0059.png new file mode 100644 index 00000000..b86df4b4 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0059.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0060.png b/assets/kenney/tiny-town/Tiles/tile_0060.png new file mode 100644 index 00000000..f8e8441e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0060.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0061.png b/assets/kenney/tiny-town/Tiles/tile_0061.png new file mode 100644 index 00000000..4b014cf6 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0061.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0062.png b/assets/kenney/tiny-town/Tiles/tile_0062.png new file mode 100644 index 00000000..1dc3f1a4 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0062.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0063.png b/assets/kenney/tiny-town/Tiles/tile_0063.png new file mode 100644 index 00000000..2964d627 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0063.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0064.png b/assets/kenney/tiny-town/Tiles/tile_0064.png new file mode 100644 index 00000000..ec8d299b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0064.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0065.png b/assets/kenney/tiny-town/Tiles/tile_0065.png new file mode 100644 index 00000000..ed6a0fa9 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0065.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0066.png b/assets/kenney/tiny-town/Tiles/tile_0066.png new file mode 100644 index 00000000..ee9ef048 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0066.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0067.png b/assets/kenney/tiny-town/Tiles/tile_0067.png new file mode 100644 index 00000000..d1ac6e7b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0067.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0068.png b/assets/kenney/tiny-town/Tiles/tile_0068.png new file mode 100644 index 00000000..7272687d Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0068.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0069.png b/assets/kenney/tiny-town/Tiles/tile_0069.png new file mode 100644 index 00000000..7d362fa5 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0069.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0070.png b/assets/kenney/tiny-town/Tiles/tile_0070.png new file mode 100644 index 00000000..e9aafdfd Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0070.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0071.png b/assets/kenney/tiny-town/Tiles/tile_0071.png new file mode 100644 index 00000000..fe5156a0 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0071.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0072.png b/assets/kenney/tiny-town/Tiles/tile_0072.png new file mode 100644 index 00000000..b3cc264c Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0072.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0073.png b/assets/kenney/tiny-town/Tiles/tile_0073.png new file mode 100644 index 00000000..d3704362 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0073.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0074.png b/assets/kenney/tiny-town/Tiles/tile_0074.png new file mode 100644 index 00000000..df9febc7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0074.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0075.png b/assets/kenney/tiny-town/Tiles/tile_0075.png new file mode 100644 index 00000000..ff1c2052 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0075.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0076.png b/assets/kenney/tiny-town/Tiles/tile_0076.png new file mode 100644 index 00000000..1262306e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0076.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0077.png b/assets/kenney/tiny-town/Tiles/tile_0077.png new file mode 100644 index 00000000..4a35d9b7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0077.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0078.png b/assets/kenney/tiny-town/Tiles/tile_0078.png new file mode 100644 index 00000000..2fa0920d Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0078.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0079.png b/assets/kenney/tiny-town/Tiles/tile_0079.png new file mode 100644 index 00000000..dbbb00d5 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0079.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0080.png b/assets/kenney/tiny-town/Tiles/tile_0080.png new file mode 100644 index 00000000..30f1b3a3 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0080.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0081.png b/assets/kenney/tiny-town/Tiles/tile_0081.png new file mode 100644 index 00000000..60fd8ab8 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0081.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0082.png b/assets/kenney/tiny-town/Tiles/tile_0082.png new file mode 100644 index 00000000..cf199cfe Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0082.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0083.png b/assets/kenney/tiny-town/Tiles/tile_0083.png new file mode 100644 index 00000000..23c6208f Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0083.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0084.png b/assets/kenney/tiny-town/Tiles/tile_0084.png new file mode 100644 index 00000000..a6e113ec Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0084.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0085.png b/assets/kenney/tiny-town/Tiles/tile_0085.png new file mode 100644 index 00000000..110d522e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0085.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0086.png b/assets/kenney/tiny-town/Tiles/tile_0086.png new file mode 100644 index 00000000..65e9eced Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0086.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0087.png b/assets/kenney/tiny-town/Tiles/tile_0087.png new file mode 100644 index 00000000..5944e653 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0087.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0088.png b/assets/kenney/tiny-town/Tiles/tile_0088.png new file mode 100644 index 00000000..fc2d6712 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0088.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0089.png b/assets/kenney/tiny-town/Tiles/tile_0089.png new file mode 100644 index 00000000..8807a4bb Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0089.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0090.png b/assets/kenney/tiny-town/Tiles/tile_0090.png new file mode 100644 index 00000000..902e6280 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0090.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0091.png b/assets/kenney/tiny-town/Tiles/tile_0091.png new file mode 100644 index 00000000..7fa18862 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0091.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0092.png b/assets/kenney/tiny-town/Tiles/tile_0092.png new file mode 100644 index 00000000..3024fbce Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0092.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0093.png b/assets/kenney/tiny-town/Tiles/tile_0093.png new file mode 100644 index 00000000..18dd4369 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0093.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0094.png b/assets/kenney/tiny-town/Tiles/tile_0094.png new file mode 100644 index 00000000..6906b6ea Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0094.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0095.png b/assets/kenney/tiny-town/Tiles/tile_0095.png new file mode 100644 index 00000000..3035e45e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0095.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0096.png b/assets/kenney/tiny-town/Tiles/tile_0096.png new file mode 100644 index 00000000..32d667f8 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0096.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0097.png b/assets/kenney/tiny-town/Tiles/tile_0097.png new file mode 100644 index 00000000..08636d5b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0097.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0098.png b/assets/kenney/tiny-town/Tiles/tile_0098.png new file mode 100644 index 00000000..17799e02 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0098.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0099.png b/assets/kenney/tiny-town/Tiles/tile_0099.png new file mode 100644 index 00000000..eafb9895 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0099.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0100.png b/assets/kenney/tiny-town/Tiles/tile_0100.png new file mode 100644 index 00000000..da234e51 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0100.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0101.png b/assets/kenney/tiny-town/Tiles/tile_0101.png new file mode 100644 index 00000000..f3dedcbe Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0101.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0102.png b/assets/kenney/tiny-town/Tiles/tile_0102.png new file mode 100644 index 00000000..321ff7a6 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0102.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0103.png b/assets/kenney/tiny-town/Tiles/tile_0103.png new file mode 100644 index 00000000..46653e0d Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0103.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0104.png b/assets/kenney/tiny-town/Tiles/tile_0104.png new file mode 100644 index 00000000..9c7c16a7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0104.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0105.png b/assets/kenney/tiny-town/Tiles/tile_0105.png new file mode 100644 index 00000000..5e1d449e Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0105.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0106.png b/assets/kenney/tiny-town/Tiles/tile_0106.png new file mode 100644 index 00000000..53309445 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0106.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0107.png b/assets/kenney/tiny-town/Tiles/tile_0107.png new file mode 100644 index 00000000..498d999f Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0107.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0108.png b/assets/kenney/tiny-town/Tiles/tile_0108.png new file mode 100644 index 00000000..f1d4db22 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0108.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0109.png b/assets/kenney/tiny-town/Tiles/tile_0109.png new file mode 100644 index 00000000..2c97ef12 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0109.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0110.png b/assets/kenney/tiny-town/Tiles/tile_0110.png new file mode 100644 index 00000000..638bdc49 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0110.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0111.png b/assets/kenney/tiny-town/Tiles/tile_0111.png new file mode 100644 index 00000000..d1883756 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0111.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0112.png b/assets/kenney/tiny-town/Tiles/tile_0112.png new file mode 100644 index 00000000..e573c74c Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0112.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0113.png b/assets/kenney/tiny-town/Tiles/tile_0113.png new file mode 100644 index 00000000..17b44f9b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0113.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0114.png b/assets/kenney/tiny-town/Tiles/tile_0114.png new file mode 100644 index 00000000..51389127 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0114.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0115.png b/assets/kenney/tiny-town/Tiles/tile_0115.png new file mode 100644 index 00000000..0325c944 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0115.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0116.png b/assets/kenney/tiny-town/Tiles/tile_0116.png new file mode 100644 index 00000000..9253174b Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0116.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0117.png b/assets/kenney/tiny-town/Tiles/tile_0117.png new file mode 100644 index 00000000..6191d7be Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0117.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0118.png b/assets/kenney/tiny-town/Tiles/tile_0118.png new file mode 100644 index 00000000..e3e58e67 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0118.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0119.png b/assets/kenney/tiny-town/Tiles/tile_0119.png new file mode 100644 index 00000000..b9da4a3c Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0119.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0120.png b/assets/kenney/tiny-town/Tiles/tile_0120.png new file mode 100644 index 00000000..9991c978 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0120.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0121.png b/assets/kenney/tiny-town/Tiles/tile_0121.png new file mode 100644 index 00000000..9ad5ce62 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0121.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0122.png b/assets/kenney/tiny-town/Tiles/tile_0122.png new file mode 100644 index 00000000..ed2d0f54 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0122.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0123.png b/assets/kenney/tiny-town/Tiles/tile_0123.png new file mode 100644 index 00000000..3958c4bf Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0123.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0124.png b/assets/kenney/tiny-town/Tiles/tile_0124.png new file mode 100644 index 00000000..029f09ba Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0124.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0125.png b/assets/kenney/tiny-town/Tiles/tile_0125.png new file mode 100644 index 00000000..c13e66b7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0125.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0126.png b/assets/kenney/tiny-town/Tiles/tile_0126.png new file mode 100644 index 00000000..50b6aca8 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0126.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0127.png b/assets/kenney/tiny-town/Tiles/tile_0127.png new file mode 100644 index 00000000..1408cfe8 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0127.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0128.png b/assets/kenney/tiny-town/Tiles/tile_0128.png new file mode 100644 index 00000000..f0ef7a05 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0128.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0129.png b/assets/kenney/tiny-town/Tiles/tile_0129.png new file mode 100644 index 00000000..3c02b6a7 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0129.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0130.png b/assets/kenney/tiny-town/Tiles/tile_0130.png new file mode 100644 index 00000000..4b995559 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0130.png differ diff --git a/assets/kenney/tiny-town/Tiles/tile_0131.png b/assets/kenney/tiny-town/Tiles/tile_0131.png new file mode 100644 index 00000000..b1c9c456 Binary files /dev/null and b/assets/kenney/tiny-town/Tiles/tile_0131.png differ diff --git a/assets/kenney/tiny-town/Tilesheet.txt b/assets/kenney/tiny-town/Tilesheet.txt new file mode 100644 index 00000000..3ecbdd2a --- /dev/null +++ b/assets/kenney/tiny-town/Tilesheet.txt @@ -0,0 +1,9 @@ +Tilesheet information: + +Tile size • 16px × 16px +Space between tiles • 1px × 1px +--- +Total tiles (horizontal) • 12 tiles +Total tiles (vertical) • 11 tiles +--- +Total tiles in sheet • 132 tiles \ No newline at end of file diff --git a/assets/kenney/tiny-town/Tiny Dungeon (base pack).url b/assets/kenney/tiny-town/Tiny Dungeon (base pack).url new file mode 100644 index 00000000..e3b16d3a --- /dev/null +++ b/assets/kenney/tiny-town/Tiny Dungeon (base pack).url @@ -0,0 +1,6 @@ +[InternetShortcut] +URL=https://kenney.nl/assets/tiny-dungeon +IDList= +HotKey=0 +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 diff --git a/assets/kenney/tiny-town/Visit Kenney.url b/assets/kenney/tiny-town/Visit Kenney.url new file mode 100644 index 00000000..c220c41b --- /dev/null +++ b/assets/kenney/tiny-town/Visit Kenney.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=http://www.kenney.nl/ \ No newline at end of file diff --git a/assets/kenney/tiny-town/Visit Patreon.url b/assets/kenney/tiny-town/Visit Patreon.url new file mode 100644 index 00000000..67e9ea57 --- /dev/null +++ b/assets/kenney/tiny-town/Visit Patreon.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://www.patreon.com/kenney/ \ No newline at end of file diff --git a/assets/ui/panel.png b/assets/ui/panel.png new file mode 100644 index 00000000..7c9fa1fd Binary files /dev/null and b/assets/ui/panel.png differ diff --git a/build-cli.sh b/build-cli.sh new file mode 100755 index 00000000..cad36c76 --- /dev/null +++ b/build-cli.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# build-cli.sh — build the self-hosted Ludic front-end binaries. +# +# Both `ludicc` and `ludic` are the SAME native binary, compiled from the Ludic +# compiler's own IR seed (selfhost/ludicc.seed.ll) with clang alone — no C +# compiler. The binary is multi-call: it looks at argv[0], so invoked as +# `ludicc` it compiles, and invoked as `ludic` it compiles and runs. +# +# ./build-cli.sh +# ./ludicc examples/snake.ludic -o build/snake # compile +# ./ludic examples/snake.ludic # compile + play +# +# The binaries locate the runtime (runtime/native/cocoa.ll) via $LUDIC_HOME, +# defaulting to the directory they sit in — so keep them at the repo root, or +# set LUDIC_HOME and put them on your PATH. +set -eu +cd "$(dirname "$0")" +CC="${LUDIC_CC:-clang}" +mkdir -p build + +echo "cc: selfhost/ludicc.seed.ll -> ludicc/ludic (from the IR seed, no C compiler)" +$CC selfhost/ludicc.seed.ll -o build/ludicc +cp build/ludicc ludicc +cp build/ludicc ludic +chmod +x ludicc ludic +echo "done. built ./ludicc and ./ludic" diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..9cc303ec --- /dev/null +++ b/build.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# build.sh — compile a Ludic program with the self-hosted Ludic compiler. +# +# The compiler is written in Ludic (selfhost/*.ludic). It is built from the +# checked-in LLVM-IR seed (selfhost/ludicc.seed.ll) with clang alone — no C +# compiler is involved anywhere. clang then assembles the emitted IR and links +# it; a windowed build also links the hand-written platform layer (cocoa.ll). +# +# ./build.sh examples/snake.ludic # windowed native app +# ./build.sh examples/snake.ludic --headless # headless (renders out.ppm) +set -u +cd "$(dirname "$0")" +CC="${LUDIC_CC:-clang}" +mkdir -p build + +# the compiler itself: assembled from the IR seed (C-free) +if [ ! -x build/ludicc ] || [ selfhost/ludicc.seed.ll -nt build/ludicc ]; then + echo "cc: selfhost/ludicc.seed.ll -> build/ludicc (from the IR seed, no C compiler)" + $CC selfhost/ludicc.seed.ll -o build/ludicc || exit 1 +fi + +SRC=""; MODE=windowed; SAVE=0 +for a in "$@"; do + case "$a" in + --headless) MODE=headless ;; + --windowed) MODE=windowed ;; + --save-temps) SAVE=1 ;; + -*) ;; + *) SRC="$a" ;; + esac +done +[ -n "$SRC" ] || { echo "usage: ./build.sh [--headless]"; exit 1; } +NAME="$(basename "${SRC%.ludic}")" + +case "$MODE" in + windowed) + OUT="build/$NAME" + echo "ludicc: $SRC -> $OUT (Ludic-written compiler -> LLVM IR -> windowed binary)" + build/ludicc --windowed "$SRC" > "$OUT.ll" || exit 1 + $CC -O2 "$OUT.ll" runtime/native/cocoa.ll -framework Cocoa -Wl,-rpath,@loader_path -o "$OUT" || exit 1 + [ "$SAVE" = 1 ] || rm -f "$OUT.ll" + echo "done. run: ./$OUT (from the repo root, so assets/ resolves)" + ;; + headless) + OUT="build/${NAME}_headless" + echo "ludicc: $SRC -> $OUT (renders the last frame to out.ppm)" + build/ludicc --headless "$SRC" > "$OUT.ll" || exit 1 + $CC -O2 "$OUT.ll" -o "$OUT" || exit 1 + [ "$SAVE" = 1 ] || rm -f "$OUT.ll" + echo "done. run: printf 'ddss' | ./$OUT && open out.ppm" + ;; +esac diff --git a/examples/chronorift.ludic b/examples/chronorift.ludic new file mode 100644 index 00000000..2f6fd3b7 --- /dev/null +++ b/examples/chronorift.ludic @@ -0,0 +1,16 @@ +# ============================================================================ +# chronorift.ludic — a 2D windowed co-op JRPG written in Ludic (CC0 Kenney art) +# Overworld + dungeon + random encounters + co-op turn battle + boss + save. +# Compiles to a native macOS app: ludicc -> LLVM IR -> native binary. No C. +# +# This entry file is deliberately thin: the game is split across modules under +# chronorift/, pulled in with `import`. Paths resolve relative to this file, and +# each import is include-guarded so re-imports are free. +# ============================================================================ +game ChronoRift { + import "chronorift/world.ludic" # components, entity archetypes, constants + import "chronorift/rules.ludic" # pure rules + map data (functions) + import "chronorift/overworld.ludic" # boot, movement, encounters, shop + import "chronorift/combat.ludic" # co-op turn battle state machine + import "chronorift/draw.ludic" # the Render system +} diff --git a/examples/chronorift/combat.ludic b/examples/chronorift/combat.ludic new file mode 100644 index 00000000..2cd46165 --- /dev/null +++ b/examples/chronorift/combat.ludic @@ -0,0 +1,167 @@ +# combat.ludic — the co-op turn-based battle state machine. + +# The battle is a state machine over R_PHASE. `machine` dispatches on the +# register and `become` transitions to a named state — no more `if ph == N` +# ladders. Knight turn (0,1), Mage turn (2,3), Enemy turn (4). +system Battle phase Update { + if reg(R_MODE) == 1 { + let k = key() + for (e) in query [Stats, {Enemy}] { + machine R_PHASE { + + state KnightMenu = 0 { + for (st, pt) in query [Stats, Party] { + if pt.slot == 0 { + if st.hp <= 0 { + become MageMenu + setreg(R_CUR, 0) + } else { + if k == 'w' { setreg(R_CUR, max(0, reg(R_CUR) - 1)) } + if k == 's' { setreg(R_CUR, min(3, reg(R_CUR) + 1)) } + if is_confirm(k) { + match reg(R_CUR) { + 0 => { + let d = max(1, st.atk - e.def + rng_range(0, 4)) + e.hp = e.hp - d + setreg(R_PDMG, d) + } + 1 => { st.guard = 1 setreg(R_PDMG, 0) } + 2 => { + if reg(R_POTION) > 0 { + setreg(R_POTION, reg(R_POTION) - 1) + st.hp = min(st.maxhp, st.hp + 24) + setreg(R_PDMG, 24) + } else { setreg(R_PDMG, 0) } + } + 3 => { + if rng_chance(50) { e.hp = 0 setreg(R_MODE, 0) } + else { setreg(R_PDMG, 0) } + } + } + become KnightResolve + setreg(R_CUR, 0) + } + } + } + } + } + + state KnightResolve = 1 { + if k != 0 { + if e.hp <= 0 { + grant_xp(e.xp) + setreg(R_GOLD, reg(R_GOLD) + e.xp) + if reg(R_ETYPE) == 2 { setreg(R_BOSS, 1) setreg(R_MODE, 3) setreg(R_ACK, 0) } + else { setreg(R_MODE, 0) } + become KnightMenu + } else { + become MageMenu + setreg(R_CUR, 0) + } + } + } + + state MageMenu = 2 { + for (st, pt) in query [Stats, Party] { + if pt.slot == 1 { + if st.hp <= 0 { + become EnemyTurn + } else { + if k == 'i' { setreg(R_CUR, max(0, reg(R_CUR) - 1)) } + if k == 'k' { setreg(R_CUR, min(2, reg(R_CUR) + 1)) } + if k == 'j' { + match reg(R_CUR) { + 0 => { + let d = max(1, st.atk + 5 - e.def + rng_range(0, 5)) + e.hp = e.hp - d + setreg(R_PDMG, d) + } + 1 => { + if st.mp >= 4 { + st.mp = st.mp - 4 + for (t2, p2) in query [Stats, Party] { + if p2.slot == 0 { t2.hp = min(t2.maxhp, t2.hp + 16) } + } + setreg(R_PDMG, 16) + } else { setreg(R_PDMG, 0) } + } + 2 => { st.guard = 1 setreg(R_PDMG, 0) } + } + become MageResolve + setreg(R_CUR, 0) + } + } + } + } + } + + state MageResolve = 3 { + if k != 0 { + if e.hp <= 0 { + grant_xp(e.xp) + setreg(R_GOLD, reg(R_GOLD) + e.xp) + if reg(R_ETYPE) == 2 { setreg(R_BOSS, 1) setreg(R_MODE, 3) setreg(R_ACK, 0) } + else { setreg(R_MODE, 0) } + become KnightMenu + } else { + become EnemyTurn + } + } + } + + state EnemyTurn = 4 { + if k != 0 { + let done = 0 + for (t3) in query [Stats, {Party}] { + if done == 0 { + if t3.hp > 0 { + let ed = max(1, e.atk - t3.def + rng_range(0, 4)) + if t3.guard == 1 { ed = ed / 2 t3.guard = 0 } + t3.hp = t3.hp - ed + setreg(R_EDMG, ed) + done = 1 + } + } + } + let alive = 0 + for (t4) in query [Stats, {Party}] { + if t4.hp > 0 { alive = alive + 1 } + } + if alive == 0 { setreg(R_MODE, 2) setreg(R_ACK, 0) } + else { + become KnightMenu + setreg(R_CUR, 0) + } + } + } + } + } + } +} + +system CleanBattle phase LateUpdate { + if reg(R_MODE) != 1 { + for (e) in query [Stats, {Enemy}] { + despawn self() + } + } +} + +system Meta phase Update { + let k = key() + if reg(R_MODE) == 2 { + if k == 0 { setreg(R_ACK, 1) } + if k != 0 { + if reg(R_ACK) == 1 { + for (h) in query [Stats, {Party}] { h.hp = h.maxhp } + setreg(R_MODE, 0) + } + } + } + if reg(R_MODE) == 3 { + if k == 0 { setreg(R_ACK, 1) } + if k != 0 { + if reg(R_ACK) == 1 { setreg(R_MODE, 0) } + } + } +} diff --git a/examples/chronorift/draw.ludic b/examples/chronorift/draw.ludic new file mode 100644 index 00000000..13259b71 --- /dev/null +++ b/examples/chronorift/draw.ludic @@ -0,0 +1,138 @@ +# draw.ludic — the Render system (overworld, battle, and overlay screens). + +system Draw phase Render { + let m = reg(R_MODE) + clear(0x101018) + + if m == 0 { + let cx = 0 + let cy = 0 + for (p) in query [Pos, {Player}] { + cx = clamp(p.x * 16 - 152, 0, MW * 16 - 320) + cy = clamp(p.y * 16 - 112, 0, MH * 16 - 240) + } + let tx0 = cx / 16 + let ty0 = cy / 16 + for ty in ty0 .. ty0 + 16 { + for tx in tx0 .. tx0 + 21 { + let c = tile(tx, ty) + let sx = tx * 16 - cx + let sy = ty * 16 - cy + let base = SPR_GRASS + match c { + 'r' => base = SPR_PATH + ',', 'S', 'B' => base = SPR_FLOOR + '=' => base = SPR_WALL + } + draw_sprite(base, sx, sy) + if c == 'T' { draw_sprite(SPR_TREE, sx, sy) } + if c == '#' { draw_sprite(SPR_TREE, sx, sy) } + if c == 'H' { draw_sprite(SPR_HOUSE, sx, sy) } + if c == 'D' { draw_sprite(SPR_DOOR, sx, sy) } + if c == 'S' { draw_sprite(SPR_DOOR, sx, sy) } + if c == 'B' { + if reg(R_BOSS) == 0 { draw_sprite(SPR_BOSS, sx, sy) } + } + } + } + for (p, a) in query [Pos, Actor] { + draw_sprite(a.kind, p.x * 16 - cx, p.y * 16 - cy) + } + for (h, pp) in query [Stats, Party] { + if pp.slot == 0 { + fill_rect(4, 4, 96, 38, 0x0c0c16) + frame_rect(4, 4, 96, 38, 0x3a3a55) + text(8, 8, "LV", 0xffe08a, 1) + text_int(24, 8, h.lvl, 0xffffff, 1) + text(8, 18, "HP", 0x88ff88, 1) + text_int(24, 18, h.hp, 0xffffff, 1) + text(8, 28, "G", 0xffd24a, 1) + text_int(18, 28, reg(R_GOLD), 0xffffff, 1) + text(54, 28, "PO", 0x88ffcc, 1) + text_int(72, 28, reg(R_POTION), 0xffffff, 1) + } + } + } + + if m == 1 { + fill_rect(0, 0, 320, 176, 0x241a2e) + for (e, a) in query [Stats, Actor, {Enemy}] { + let bs = 5 + if reg(R_ETYPE) == 2 { bs = 7 } + draw_sprite_scaled(a.kind, 160 - bs * 8, 44, bs) + text(100, 20, enemy_name(reg(R_ETYPE)), 0xffffff, 1) + fill_rect(100, 30, 120, 8, 0x401018) + fill_rect(100, 30, e.hp * 120 / e.maxhp, 8, 0xe04040) + } + let ph = reg(R_PHASE) + let act = 0 + if ph >= 2 { act = 1 } + if ph >= 4 { act = 2 } + fill_rect(0, 176, 320, 64, 0x0c0c16) + frame_rect(0, 176, 320, 64, 0x3a3a55) + for (st, pt) in query [Stats, Party] { + let hx = 6 + pt.slot * 92 + let spr = 5 + if pt.slot == 1 { spr = 9 } + if pt.slot == act { frame_rect(hx - 2, 180, 88, 44, 0xffff00) } + draw_sprite_scaled(spr, hx, 184, 2) + if pt.slot == 0 { text(hx + 36, 182, "KNIGHT", 0xffe08a, 1) } + if pt.slot == 1 { text(hx + 36, 182, "MAGE", 0xc9a0ff, 1) } + text(hx + 36, 195, "HP", 0x88ff88, 1) + text_int(hx + 56, 195, st.hp, 0xffffff, 1) + text(hx + 36, 207, "MP", 0x88aaff, 1) + text_int(hx + 56, 207, st.mp, 0xffffff, 1) + } + let cur = reg(R_CUR) + if ph == 0 or ph == 1 { + text(206, 181, "P1 KNIGHT", 0xffe08a, 1) + text(214, 192, "ATTACK", 0xffffff, 1) + text(214, 203, "DEFEND", 0xffffff, 1) + text(214, 214, "ITEM", 0xffffff, 1) + text(256, 214, "x", 0x777777, 1) + text_int(264, 214, reg(R_POTION), 0xffd24a, 1) + text(214, 225, "RUN", 0xffffff, 1) + if ph == 0 { text(204, 192 + cur * 11, ">", 0xffff00, 1) } + } + if ph == 2 or ph == 3 { + text(206, 182, "P2 MAGE", 0xc9a0ff, 1) + text(214, 196, "ATTACK", 0xffffff, 1) + text(214, 208, "HEAL", 0xffffff, 1) + text(214, 220, "DEFEND", 0xffffff, 1) + if ph == 2 { text(204, 196 + cur * 12, ">", 0xffff00, 1) } + } + if ph == 4 { text(206, 200, "ENEMY TURN", 0xff8888, 1) } + if ph == 1 or ph == 3 { + text(6, 232, "DMG", 0xffff88, 1) + text_int(34, 232, reg(R_PDMG), 0xffffff, 1) + } + if ph == 4 { + text(6, 232, "FOE HITS", 0xff8888, 1) + text_int(66, 232, reg(R_EDMG), 0xffffff, 1) + } + } + + if m == 2 { + text(112, 104, "YOU FELL", 0xff5555, 2) + text(84, 140, "PRESS ANY KEY", 0xffffff, 1) + } + if m == 3 { + text(60, 96, "THE RIFT IS SEALED", 0x88ffcc, 2) + text(96, 132, "VICTORY!", 0xffe060, 3) + text(84, 170, "PRESS ANY KEY", 0xffffff, 1) + } + if m == 4 { + fill_rect(60, 60, 200, 120, 0x141422) + frame_rect(60, 60, 200, 120, 0x6a6a95) + text(96, 72, "ITEM SHOP", 0xffe060, 2) + text(80, 104, "BUY POTION", 0xffffff, 1) + text(180, 104, "10 G", 0xffd24a, 1) + text(80, 122, "LEAVE", 0xffffff, 1) + text(70, 104 + reg(R_CUR) * 18, ">", 0xffff00, 1) + text(80, 150, "GOLD", 0xffd24a, 1) + text_int(120, 150, reg(R_GOLD), 0xffffff, 1) + text(160, 150, "POTIONS", 0x88ffcc, 1) + text_int(226, 150, reg(R_POTION), 0xffffff, 1) + } + present() +} diff --git a/examples/chronorift/overworld.ludic b/examples/chronorift/overworld.ludic new file mode 100644 index 00000000..3ce11c01 --- /dev/null +++ b/examples/chronorift/overworld.ludic @@ -0,0 +1,140 @@ +# overworld.ludic — boot, movement/encounter input, and the shop system. + +system Boot phase Start { + load_png("assets/kenney/tiny-town/Tiles/tile_0000.png") # 0 grass + load_png("assets/kenney/tiny-town/Tiles/tile_0004.png") # 1 tree + load_png("assets/kenney/tiny-town/Tiles/tile_0025.png") # 2 path + load_png("assets/kenney/tiny-town/Tiles/tile_0073.png") # 3 house + load_png("assets/kenney/tiny-town/Tiles/tile_0112.png") # 4 arch + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0096.png") # 5 hero + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0108.png") # 6 slime + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0120.png") # 7 skeleton + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0110.png") # 8 boss + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0084.png") # 9 mage + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0048.png") # 10 floor + load_png("assets/kenney/tiny-dungeon/Tiles/tile_0026.png") # 11 wall + + build_field(0) + spawn Player { + Pos = { x = 11, y = 15 } + Actor = { kind = 5 } + Party = { slot = 0 } + Stats = { hp = 40, maxhp = 40, mp = 8, maxmp = 8, atk = 12, def = 6, lvl = 1, xp = 0, guard = 0 } + } + spawn Ally { + Party = { slot = 1 } + Stats = { hp = 26, maxhp = 26, mp = 16, maxmp = 16, atk = 8, def = 4, lvl = 1, xp = 0, guard = 0 } + } + setreg(R_MODE, 0) + setreg(R_ENC, 4) + setreg(R_MAP, 0) + setreg(R_BOSS, 0) + setreg(R_GOLD, 20) + setreg(R_POTION, 2) +} + +system Control phase Input { + if reg(R_MODE) == 0 { + for (p) in query [Pos, {Player}] { + let k = key() + let nx = p.x + let ny = p.y + if k == 'w' { ny = p.y - 1 } + if k == 's' { ny = p.y + 1 } + if k == 'a' { nx = p.x - 1 } + if k == 'd' { nx = p.x + 1 } + let moved = 0 + if walkable(nx, ny) { + if nx != p.x or ny != p.y { + p.x = nx + p.y = ny + moved = 1 + } + } + if moved == 1 { + let tc = tile(p.x, p.y) + if tc == 'D' { + build_dungeon(0) + p.x = 3 + p.y = 2 + setreg(R_MAP, 1) + } + if tc == 'S' { + build_field(0) + p.x = 36 + p.y = 3 + setreg(R_MAP, 0) + } + if tc == 'B' { + if reg(R_BOSS) == 0 { + setreg(R_ETYPE, 2) + spawn Enemy { + Actor = { kind = 8 } + Stats = { hp = 120, maxhp = 120, mp = 0, maxmp = 0, atk = 18, def = 10, lvl = 5, xp = 300, guard = 0 } + } + setreg(R_MODE, 1) + setreg(R_PHASE, 0) + setreg(R_CUR, 0) + } + } + if tc == 'h' { + setreg(R_MODE, 4) + setreg(R_CUR, 0) + } + if tc != 'D' { + if tc != 'S' { + if tc != 'B' { + if tc != 'h' { + setreg(R_ENC, reg(R_ENC) - 1) + if reg(R_ENC) <= 0 { + setreg(R_ENC, rng_range(4, 9)) + let et = 0 + if reg(R_MAP) == 1 { et = 1 } + if reg(R_MAP) == 0 { + if rng_chance(40) { et = 1 } + } + setreg(R_ETYPE, et) + if et == 0 { + spawn Enemy { + Actor = { kind = 6 } + Stats = { hp = 18, maxhp = 18, mp = 0, maxmp = 0, atk = 8, def = 2, lvl = 1, xp = 7, guard = 0 } + } + } + if et == 1 { + spawn Enemy { + Actor = { kind = 7 } + Stats = { hp = 30, maxhp = 30, mp = 0, maxmp = 0, atk = 11, def = 5, lvl = 1, xp = 15, guard = 0 } + } + } + setreg(R_MODE, 1) + setreg(R_PHASE, 0) + setreg(R_CUR, 0) + } + } + } + } + } + } + if k == 'k' { save() } + if k == 'l' { if load() { } } + } + } +} + +# shop (at the house 'h' tile): buy potions with gold +system Shop phase Update { + if reg(R_MODE) == 4 { + let k = key() + if k == 'w' { setreg(R_CUR, max(0, reg(R_CUR) - 1)) } + if k == 's' { setreg(R_CUR, min(1, reg(R_CUR) + 1)) } + if is_confirm(k) { + if reg(R_CUR) == 0 { + if reg(R_GOLD) >= 10 { + setreg(R_GOLD, reg(R_GOLD) - 10) + setreg(R_POTION, reg(R_POTION) + 1) + } + } + if reg(R_CUR) == 1 { setreg(R_MODE, 0) } + } + } +} diff --git a/examples/chronorift/rules.ludic b/examples/chronorift/rules.ludic new file mode 100644 index 00000000..12d77dc8 --- /dev/null +++ b/examples/chronorift/rules.ludic @@ -0,0 +1,86 @@ +# rules.ludic — pure game rules & map data (functions only, no systems). + +fn tile_sprite(c: int) -> int { + match c { + 'T', '#' => return SPR_TREE + 'H' => return SPR_HOUSE + 'D' => return SPR_DOOR + 'r', 'h' => return SPR_PATH + ',', 'S', 'B' => return SPR_FLOOR + '=' => return SPR_WALL + } + return SPR_GRASS +} +fn walkable(x: int, y: int) -> bool { + let c = tile(x, y) + return c == '.' or c == 'D' or c == 'r' or c == ',' or c == 'S' or c == 'B' or c == 'h' +} +fn is_confirm(k: int) -> bool { return k == 32 or k == 10 or k == 13 } +fn enemy_name(et: int) -> str { + if et == 0 { return "SLIME" } + if et == 1 { return "SKELETON" } + return "RIFT WARDEN" +} + +fn build_field(x: int) -> int { + map_size(40, 18) + map_row(0, "########################################") + map_row(1, "#......................................#") + map_row(2, "#...TT.........................TT.....D#") + map_row(3, "#..TT.......................TT.........#") + map_row(4, "#..T.........................T.........#") + map_row(5, "#....................................T.#") + map_row(6, "#.....TT....................TT.......T.#") + map_row(7, "#....TT.....................T..........#") + map_row(8, "#...........rrrrrrrr........HH.........#") + map_row(9, "#..........r........r.......HH.........#") + map_row(10, "#......TT...r........rrrrrrrrhr......T.#") + map_row(11, "#.....TT...r.................r.......T.#") + map_row(12, "#..........r.......TT.......r..........#") + map_row(13, "#..........rrrrrrrrrrrrrrrrr.........T.#") + map_row(14, "#.........TT.........................T.#") + map_row(15, "#........TT..........................T.#") + map_row(16, "#....................................T.#") + map_row(17, "########################################") + return 0 +} +fn build_dungeon(x: int) -> int { + map_size(40, 18) + map_row(0, "========================================") + map_row(1, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(2, "=,S,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(3, "=,,,,,====,,,,,,,,,,,,,,,====,,,,,,,,,,=") + map_row(4, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(5, "=,,,,,,,,,,,,,====,,,,,,,,,,,,,,,,,,,,,=") + map_row(6, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,====,,,,,=") + map_row(7, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(8, "=,,,====,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(9, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(10, "=,,,,,,,,,,,,,,,,,,====,,,,,,,,,,,,,,,,=") + map_row(11, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(12, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,====,,,,,,,=") + map_row(13, "=,,,,,,,,,====,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(14, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(15, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,B,,=") + map_row(16, "=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=") + map_row(17, "========================================") + return 0 +} + +fn grant_xp(amount: int) -> int { + for (t) in query [Stats, {Party}] { + if t.hp > 0 { + t.xp = t.xp + amount + while t.xp >= t.lvl * 20 { + t.xp = t.xp - t.lvl * 20 + t.lvl = t.lvl + 1 + t.maxhp = t.maxhp + 8 + t.hp = t.maxhp + t.maxmp = t.maxmp + 2 + t.atk = t.atk + 2 + t.def = t.def + 1 + } + } + } + return 0 +} diff --git a/examples/chronorift/world.ludic b/examples/chronorift/world.ludic new file mode 100644 index 00000000..457d87ee --- /dev/null +++ b/examples/chronorift/world.ludic @@ -0,0 +1,43 @@ +# world.ludic — the data model: components, entity archetypes, constants. +# Imported by examples/chronorift.ludic. No `game` wrapper (this is a fragment). + +component Pos { x: int = 0, y: int = 0 } +component Actor { kind: int = 0 } +component Stats { hp: int = 1, maxhp: int = 1, mp: int = 0, maxmp: int = 0, + atk: int = 1, def: int = 0, lvl: int = 1, xp: int = 0, guard: int = 0 } +component Party { slot: int = 0 } + +# Entity KINDS. Identity is stored as one integer per entity (L_kind), not as +# an empty marker component. Query membership with {Player} / {Enemy}. +archetype Player { Pos, Actor, Party, Stats } # the controllable knight +archetype Ally { Party, Stats } # backline mage (no overworld body) +archetype Enemy { Actor, Stats } # battle foe + +const MW: int = 40 +const MH: int = 18 + +const SPR_GRASS: int = 0 +const SPR_TREE: int = 1 +const SPR_PATH: int = 2 +const SPR_HOUSE: int = 3 +const SPR_DOOR: int = 4 +const SPR_HERO: int = 5 +const SPR_SLIME: int = 6 +const SPR_SKEL: int = 7 +const SPR_BOSS: int = 8 +const SPR_MAGE: int = 9 +const SPR_FLOOR: int = 10 +const SPR_WALL: int = 11 + +const R_MODE: int = 0 # 0 field, 1 battle, 2 gameover, 3 victory +const R_PHASE: int = 1 +const R_CUR: int = 2 +const R_ENC: int = 3 +const R_ETYPE: int = 4 # 0 slime, 1 skeleton, 2 boss +const R_PDMG: int = 5 +const R_EDMG: int = 6 +const R_GOLD: int = 7 +const R_MAP: int = 8 # 0 overworld, 1 dungeon +const R_BOSS: int = 9 # boss defeated flag +const R_ACK: int = 10 # debounce for end screens +const R_POTION: int = 11 # potions in inventory diff --git a/examples/hello.ludic b/examples/hello.ludic new file mode 100644 index 00000000..0b4d1780 --- /dev/null +++ b/examples/hello.ludic @@ -0,0 +1,34 @@ +# hello.ludic — smallest program that exercises the ECS pipeline +game Hello { + + component Pos { x: int = 0, y: int = 0 } + component Vel { dx: int = 0, dy: int = 0 } + + system Boot phase Start { + spawn Mob { + Pos = { x = 3, y = 4 } + Vel = { dx = 1, dy = 0 } + } + spawn Mob { + Pos = { x = 10, y = 2 } + Vel = { dx = 0, dy = 1 } + } + } + + # a system can declare the entities it operates on: the body then runs once + # per match, with the components bound and self() giving that entity. + system Move phase FixedUpdate + query (p, v) [Pos, Vel] + { + p.x = p.x + v.dx + p.y = p.y + v.dy + } + + system Report phase Update { + for (p) in query [Pos] { + print_int(p.x) + print_int(p.y) + } + quit() + } +} diff --git a/examples/lib/arena.ludic b/examples/lib/arena.ludic new file mode 100644 index 00000000..35bdf6ae --- /dev/null +++ b/examples/lib/arena.ludic @@ -0,0 +1,34 @@ +# ============================================================================ +# arena.ludic — a game that links the Ludic shared library next to it. +# +# ludicc examples/lib/combat.ludic --shared -o build/libcombat.dylib +# ludicc examples/lib/arena.ludic -o build/arena -Lbuild -lcombat +# +# `extern fn` binds a name to a symbol resolved at link time. The library the +# symbols come from happens to be written in Ludic, but nothing here depends on +# that: the same declaration binds a C, Rust or Zig library just as well. This +# is how Ludic reaches the outside world without a C shim. +# ============================================================================ +game Arena { + + extern fn damage(attack: int, armour: int, roll: int) -> int = "damage" + extern fn hits_to_kill(hp: int, attack: int, armour: int) -> int = "hits_to_kill" + extern fn xp_for(level: int, kills: int) -> int = "xp_for" + + component Fighter { hp: int = 30, attack: int = 9, armour: int = 2 } + + system Boot phase Start { + spawn Hero { Fighter = { hp = 40, attack = 12, armour = 3 } } + spawn Orc { Fighter = { hp = 24, attack = 7, armour = 1 } } + } + + system Fight phase Update { + for (f) in query [Fighter] { + print_int(damage(f.attack, f.armour, 0)) + print_int(damage(f.attack, f.armour, 20)) + print_int(hits_to_kill(f.hp, f.attack, f.armour)) + } + print_int(xp_for(3, 4)) + quit() + } +} diff --git a/examples/lib/combat.ludic b/examples/lib/combat.ludic new file mode 100644 index 00000000..794f72d5 --- /dev/null +++ b/examples/lib/combat.ludic @@ -0,0 +1,46 @@ +# ============================================================================ +# combat.ludic — a Ludic *library*, not a game. +# +# `module` instead of `game` means: no entry point, no frame loop. ludicc +# compiles this to a real shared object — +# +# ludicc examples/lib/combat.ludic --shared -o build/libcombat.dylib +# +# — whose `export fn`s are ordinary C-ABI symbols. Anything that can call a +# .dylib/.so/.dll can call these: another Ludic program via `extern fn`, a game +# engine, a test harness, a scripting host. Non-exported functions stay private +# to the library. +# ============================================================================ +module Combat { + + const CRIT_MULT: int = 2 + + # damage after armour, with a crit multiplier applied on an exact roll + export fn damage(attack: int, armour: int, roll: int) -> int { + let raw = attack - armour + if raw < 1 { raw = 1 } + if roll == 20 { raw = raw * CRIT_MULT } + return raw + } + + # how many hits to drop a target — the loop is here so the caller cannot + # accidentally disagree with `damage` about rounding + export fn hits_to_kill(hp: int, attack: int, armour: int) -> int { + let left = hp + let n = 0 + while left > 0 { + left = left - damage(attack, armour, 0) + n = n + 1 + } + return n + } + + export fn xp_for(level: int, kills: int) -> int { + return curve(level) * kills + } + + # private: not exported, so it is not a symbol in the library + fn curve(level: int) -> int { + return 10 + level * level * 3 + } +} diff --git a/examples/menu.ludic b/examples/menu.ludic new file mode 100644 index 00000000..2bb9861e --- /dev/null +++ b/examples/menu.ludic @@ -0,0 +1,41 @@ +# menu.ludic — a retained-UI title screen. The UI is declared as DATA (the `ui` +# block); the engine lays it out (stacked panel, padding/gap/alignment), draws +# it (background, TrueType labels, focusable buttons), and routes keyboard focus +# and activation. The game only loads a font, opens the UI, and reads clicks. +game Menu { + + const R_FONT: int = 0 + const R_MSG: int = 1 + + ui MainMenu { + panel id=Root w=288 pad=16 gap=6 bg=0x1a1a2c border=0x4a4a72 skin="assets/ui/panel.png" inset=10 align=center { + label text="CHRONO RIFT" font=reg(R_FONT) size=26 fg=0xffe060 align=center + label text="a Ludic retained-UI demo" font=reg(R_FONT) size=14 fg=0x9aa0c8 align=center + spacer h=4 + button id=NewGame text="New Game" font=reg(R_FONT) size=16 w=236 + button id=Continue text="Continue" font=reg(R_FONT) size=16 w=236 + button id=Options text="Options" font=reg(R_FONT) size=16 w=236 + button id=Quit text="Quit" font=reg(R_FONT) size=16 w=236 + } + } + + system Boot phase Start { + setreg(R_FONT, font_load("/System/Library/Fonts/Supplemental/Arial.ttf")) + ui_build() + ui_open(UI_MainMenu) + } + + system Nav phase Update { + ui_tick(key()) + if ui_clicked(UI_NewGame) { ui_set_text(UI_NewGame, "Starting...") } + if ui_clicked(UI_Continue) { ui_set_text(UI_Continue, "No save") } + if ui_clicked(UI_Options) { ui_set_text(UI_Options, "Soon (TM)") } + if ui_clicked(UI_Quit) { quit() } + } + + system Draw phase Render { + clear(0x0e0e16) + ui_render() + present() + } +} diff --git a/examples/qdecl.ludic b/examples/qdecl.ludic new file mode 100644 index 00000000..5c63a879 --- /dev/null +++ b/examples/qdecl.ludic @@ -0,0 +1,37 @@ +# ============================================================================ +# qdecl.ludic — a system whose query lives in its signature. +# +# system CleanBattle phase LateUpdate +# query (b, p) [Battle, Pos, {Foe}] where b.hp <= 0 +# { … } +# +# is the same thing as writing `for (b, p) in query [...] where ... { … }` around +# the whole body — the loop header just moves into the declaration. The body runs +# once per matching entity, and self() is that entity. +# ============================================================================ +game QueryDecl { + component Battle { hp: int = 0, side: int = 0 } + component Pos { x: int = 0, y: int = 0 } + archetype Foe { Battle, Pos } + + system Seed phase Start { + spawn Foe { Battle = { hp = 3, side = 1 } } + spawn Foe { Battle = { hp = 0, side = 1 } } + spawn Foe { Battle = { hp = -2, side = 0 } } + } + + system CleanBattle phase LateUpdate + query (b, p) [Battle, Pos, {Foe}] where b.hp <= 0 and b.side == 1 + { + print_int(p.x) + despawn self() + } + + system Census phase Render + query (b) [Battle] + { + print_int(b.hp) + } + + system Bye phase Render { quit() } +} diff --git a/examples/scenes.ludic b/examples/scenes.ludic new file mode 100644 index 00000000..b3600e7b --- /dev/null +++ b/examples/scenes.ludic @@ -0,0 +1,38 @@ +# ⚠� NOT YET IMPLEMENTED by the self-hosted compiler. `scene` / `layer` / +# `on enter` / `on exit` have no parser support today, so this file does NOT +# compile with build/ludicc — it is a design sketch of the intended syntax (see +# LANGUAGE.md §"Scenes & layers"). It is deliberately excluded from test.sh. +# Games that need scene-like states use a mode register + `machine` today, as +# examples/chronorift does. +game SceneDemo { + const R_N: int = 0 + + system Boot phase Start { setreg(R_N, 0) print_int(1000) } + + scene Title start { + on enter { print_int(1) } + on exit { print_int(2) } + layer Main { + system Tick phase Update { + setreg(R_N, reg(R_N) + 1) + print_int(100 + reg(R_N)) + if reg(R_N) >= 2 { enter Play } + } + } + } + + scene Play { + on enter { print_int(3) setreg(R_N, 0) } + on exit { print_int(4) } + layer World { + system Step phase Update { + setreg(R_N, reg(R_N) + 1) + print_int(200 + reg(R_N)) + if reg(R_N) >= 2 { quit() } + } + } + layer Hud { + system Draw phase Render { print_int(900) } + } + } +} diff --git a/examples/snake.ludic b/examples/snake.ludic new file mode 100644 index 00000000..857dbe4e --- /dev/null +++ b/examples/snake.ludic @@ -0,0 +1,136 @@ +# ============================================================================ +# snake.ludic — a second, unrelated game in Ludic, to prove the language is +# general: compiled by the SAME unmodified ludicc + runtime as the JRPG. +# No sprites/assets — pure primitives. Build: ./build.sh examples/snake.ludic +# ============================================================================ +game Snake { + + component Pos { x: int = 0, y: int = 0 } + component Seg { order: int = 0 } + + const GW: int = 20 + const GH: int = 15 + const TS: int = 16 + + const R_DIR: int = 0 # 0 up 1 down 2 left 3 right + const R_LEN: int = 1 + const R_TICK: int = 2 + const R_FX: int = 3 + const R_FY: int = 4 + const R_MODE: int = 5 # 0 play 1 gameover + const R_SCORE: int = 6 + const R_ATE: int = 7 + const R_TX: int = 8 + const R_TY: int = 9 + const R_ACK: int = 10 + + fn reset(x: int) -> int { + for (p, s) in query [Pos, Seg] { despawn self() } + spawn S0 { Seg = { order = 0 } Pos = { x = 10, y = 7 } } + spawn S1 { Seg = { order = 1 } Pos = { x = 9, y = 7 } } + spawn S2 { Seg = { order = 2 } Pos = { x = 8, y = 7 } } + setreg(R_DIR, 3) + setreg(R_LEN, 3) + setreg(R_TICK, 0) + setreg(R_MODE, 0) + setreg(R_SCORE, 0) + setreg(R_FX, 14) + setreg(R_FY, 7) + return 0 + } + + system Boot phase Start { reset(0) } + + system Input phase Input { + let k = key() + if reg(R_MODE) == 0 { + if k == 'w' { if reg(R_DIR) != 1 { setreg(R_DIR, 0) } } + if k == 's' { if reg(R_DIR) != 0 { setreg(R_DIR, 1) } } + if k == 'a' { if reg(R_DIR) != 3 { setreg(R_DIR, 2) } } + if k == 'd' { if reg(R_DIR) != 2 { setreg(R_DIR, 3) } } + } + if reg(R_MODE) == 1 { + if k == 0 { setreg(R_ACK, 1) } + if k != 0 { if reg(R_ACK) == 1 { reset(0) } } + } + } + + system Move phase Update { + if reg(R_MODE) == 0 { + setreg(R_TICK, reg(R_TICK) + 1) + if reg(R_TICK) >= 6 { + setreg(R_TICK, 0) + let len = reg(R_LEN) + for (pt, stg) in query [Pos, Seg] { + if stg.order == len - 1 { setreg(R_TX, pt.x) setreg(R_TY, pt.y) } + } + for step in 0 .. len { + let i = len - 1 - step + if i >= 1 { + for (pa, sa) in query [Pos, Seg] { + if sa.order == i { + for (pb, sb) in query [Pos, Seg] { + if sb.order == i - 1 { pa.x = pb.x pa.y = pb.y } + } + } + } + } + } + setreg(R_ATE, 0) + for (ph, sh) in query [Pos, Seg] { + if sh.order == 0 { + if reg(R_DIR) == 0 { ph.y = ph.y - 1 } + if reg(R_DIR) == 1 { ph.y = ph.y + 1 } + if reg(R_DIR) == 2 { ph.x = ph.x - 1 } + if reg(R_DIR) == 3 { ph.x = ph.x + 1 } + if ph.x < 0 { setreg(R_MODE, 1) } + if ph.x >= GW { setreg(R_MODE, 1) } + if ph.y < 0 { setreg(R_MODE, 1) } + if ph.y >= GH { setreg(R_MODE, 1) } + if ph.x == reg(R_FX) { if ph.y == reg(R_FY) { setreg(R_ATE, 1) } } + } + } + for (ph, sh) in query [Pos, Seg] { + if sh.order == 0 { + for (pb, sb) in query [Pos, Seg] { + if sb.order > 0 { + if pb.x == ph.x { if pb.y == ph.y { setreg(R_MODE, 1) } } + } + } + } + } + if reg(R_ATE) == 1 { + setreg(R_SCORE, reg(R_SCORE) + 1) + spawn Body { Seg = { order = len } Pos = { x = reg(R_TX), y = reg(R_TY) } } + setreg(R_LEN, len + 1) + setreg(R_FX, rng_range(0, GW - 1)) + setreg(R_FY, rng_range(0, GH - 1)) + } + } + } + } + + system Draw phase Render { + clear(0x0d1020) + for gy in 0 .. GH { + for gx in 0 .. GW { + let col = 0x141a2e + if (gx + gy) % 2 == 0 { col = 0x10162a } + fill_rect(gx * TS, gy * TS, TS, TS, col) + } + } + fill_rect(reg(R_FX) * TS + 3, reg(R_FY) * TS + 3, TS - 6, TS - 6, 0xe0405a) + for (p, s) in query [Pos, Seg] { + let col = 0x40c060 + if s.order == 0 { col = 0x9dffb0 } + fill_rect(p.x * TS + 1, p.y * TS + 1, TS - 2, TS - 2, col) + } + text(6, 4, "SCORE", 0xffffff, 1) + text_int(52, 4, reg(R_SCORE), 0xffe060, 1) + if reg(R_MODE) == 1 { + text(112, 104, "GAME OVER", 0xff5555, 2) + text(84, 140, "PRESS ANY KEY", 0xffffff, 1) + } + present() + } +} diff --git a/runtime/native/cocoa.ll b/runtime/native/cocoa.ll new file mode 100644 index 00000000..b092b940 --- /dev/null +++ b/runtime/native/cocoa.ll @@ -0,0 +1,327 @@ +; ============================================================================ +; cocoa.ll — the macOS window, written in LLVM IR. +; +; This is what replaced plat_cocoa.m. There is no Objective-C source and no C +; source in a Ludic build: the window is opened by talking to the Objective-C +; runtime through its C ABI (objc_getClass / sel_registerName / objc_msgSend) +; and to Quartz through CoreGraphics, exactly as a compiled .m file would, only +; written at the level ludicc itself emits. ludicc splices this module in when +; it links a windowed macOS binary. +; +; The one piece that genuinely needs a class is the view: AppKit paints through +; -drawRect:, so a class is built at runtime with objc_allocateClassPair and +; @ludic_drawRect is installed as its IMP. On arm64 the unused NSRect argument +; simply stays in registers we never read, so the IMP needs no struct in its +; signature. +; +; Exposed to Ludic (through the win_* intrinsics): +; win_open(w, h, scale, title) win_poll() -> key win_present(fb, w, h) +; win_running() -> bool win_close() +; ============================================================================ + +%CGRect = type { double, double, double, double } + +declare ptr @objc_getClass(ptr) +declare ptr @sel_registerName(ptr) +declare ptr @objc_msgSend(ptr, ptr, ...) +declare ptr @objc_allocateClassPair(ptr, ptr, i64) +declare void @objc_registerClassPair(ptr) +declare i8 @class_addMethod(ptr, ptr, ptr, ptr) +declare ptr @CGColorSpaceCreateDeviceRGB() +declare ptr @CGBitmapContextCreate(ptr, i64, i64, i64, i64, ptr, i32) +declare ptr @CGBitmapContextCreateImage(ptr) +declare void @CGContextDrawImage(ptr, %CGRect, ptr) +declare void @CGContextSetInterpolationQuality(ptr, i32) +declare void @CGContextTranslateCTM(ptr, double, double) +declare void @CGContextScaleCTM(ptr, double, double) +declare void @CGContextSaveGState(ptr) +declare void @CGContextRestoreGState(ptr) +declare void @CGImageRelease(ptr) +declare void @CGContextRelease(ptr) +declare void @CGColorSpaceRelease(ptr) +declare i32 @usleep(i32) + +@.c_app = private unnamed_addr constant [14 x i8] c"NSApplication\00" +@.c_win = private unnamed_addr constant [9 x i8] c"NSWindow\00" +@.c_str = private unnamed_addr constant [9 x i8] c"NSString\00" +@.c_date = private unnamed_addr constant [7 x i8] c"NSDate\00" +@.c_view = private unnamed_addr constant [7 x i8] c"NSView\00" +@.c_gctx = private unnamed_addr constant [18 x i8] c"NSGraphicsContext\00" +@.c_ludic = private unnamed_addr constant [10 x i8] c"LudicView\00" + +@.s_shared = private unnamed_addr constant [18 x i8] c"sharedApplication\00" +@.s_policy = private unnamed_addr constant [21 x i8] c"setActivationPolicy:\00" +@.s_alloc = private unnamed_addr constant [6 x i8] c"alloc\00" +@.s_initw = private unnamed_addr constant [45 x i8] c"initWithContentRect:styleMask:backing:defer:\00" +@.s_initf = private unnamed_addr constant [15 x i8] c"initWithFrame:\00" +@.s_title = private unnamed_addr constant [10 x i8] c"setTitle:\00" +@.s_utf8 = private unnamed_addr constant [22 x i8] c"stringWithUTF8String:\00" +@.s_setcv = private unnamed_addr constant [16 x i8] c"setContentView:\00" +@.s_center = private unnamed_addr constant [7 x i8] c"center\00" +@.s_mkey = private unnamed_addr constant [22 x i8] c"makeKeyAndOrderFront:\00" +@.s_mfirst = private unnamed_addr constant [20 x i8] c"makeFirstResponder:\00" +@.s_act = private unnamed_addr constant [27 x i8] c"activateIgnoringOtherApps:\00" +@.s_next = private unnamed_addr constant [48 x i8] c"nextEventMatchingMask:untilDate:inMode:dequeue:\00" +@.s_send = private unnamed_addr constant [11 x i8] c"sendEvent:\00" +@.s_dpast = private unnamed_addr constant [12 x i8] c"distantPast\00" +@.s_type = private unnamed_addr constant [5 x i8] c"type\00" +@.s_keycd = private unnamed_addr constant [8 x i8] c"keyCode\00" +@.s_chars = private unnamed_addr constant [28 x i8] c"charactersIgnoringModifiers\00" +@.s_length = private unnamed_addr constant [7 x i8] c"length\00" +@.s_charat = private unnamed_addr constant [18 x i8] c"characterAtIndex:\00" +@.s_disp = private unnamed_addr constant [8 x i8] c"display\00" +@.s_visib = private unnamed_addr constant [10 x i8] c"isVisible\00" +@.s_curctx = private unnamed_addr constant [15 x i8] c"currentContext\00" +@.s_cgctx = private unnamed_addr constant [10 x i8] c"CGContext\00" +@.s_drawr = private unnamed_addr constant [10 x i8] c"drawRect:\00" +@.s_afr = private unnamed_addr constant [23 x i8] c"acceptsFirstResponder\00\00" +@.mode = private unnamed_addr constant [22 x i8] c"kCFRunLoopDefaultMode\00" +@.enc_draw = private unnamed_addr constant [36 x i8] c"v@:{CGRect={CGPoint=dd}{CGSize=dd}}\00" +@.enc_bool = private unnamed_addr constant [4 x i8] c"c@:\00" + +@W_app = internal global ptr null +@W_win = internal global ptr null +@W_view = internal global ptr null +@W_fb = internal global ptr null +@W_fbw = internal global i32 320 +@W_fbh = internal global i32 240 +@W_scale = internal global i32 3 +@W_key = internal global i32 0 +@W_running = internal global i32 1 + +; -drawRect: — blit the framebuffer into the view. +; The NSRect argument is ignored, so it never appears in this signature. +define internal void @ludic_drawRect(ptr %self, ptr %sel) { +entry: + %fb = load ptr, ptr @W_fb + %null = icmp eq ptr %fb, null + br i1 %null, label %out, label %draw +draw: + %w32 = load i32, ptr @W_fbw + %h32 = load i32, ptr @W_fbh + %sc32 = load i32, ptr @W_scale + %w = sext i32 %w32 to i64 + %h = sext i32 %h32 to i64 + %stride = mul i64 %w, 4 + + %cs = call ptr @CGColorSpaceCreateDeviceRGB() + ; kCGImageAlphaNoneSkipFirst (6) | kCGBitmapByteOrder32Little (8192) + %bmp = call ptr @CGBitmapContextCreate(ptr %fb, i64 %w, i64 %h, i64 8, i64 %stride, ptr %cs, i32 8198) + %img = call ptr @CGBitmapContextCreateImage(ptr %bmp) + + %gcls = call ptr @objc_getClass(ptr @.c_gctx) + %sel_cur = call ptr @sel_registerName(ptr @.s_curctx) + %gctx = call ptr @objc_msgSend(ptr %gcls, ptr %sel_cur) + %sel_cg = call ptr @sel_registerName(ptr @.s_cgctx) + %ctx = call ptr @objc_msgSend(ptr %gctx, ptr %sel_cg) + + call void @CGContextSetInterpolationQuality(ptr %ctx, i32 1) ; kCGInterpolationNone + %scd = sitofp i32 %sc32 to double + %wd = sitofp i32 %w32 to double + %hd = sitofp i32 %h32 to double + %dw = fmul double %wd, %scd + %dh = fmul double %hd, %scd + + ; The framebuffer's row 0 is the top row, and a CGImage built over it carries + ; that orientation, so drawing it into the view's context lands right-side-up + ; with no CTM flip. (Adding one here mirrors the game vertically — verified by + ; drawing four different corners and looking at the window.) + %r0 = insertvalue %CGRect undef, double 0.0, 0 + %r1 = insertvalue %CGRect %r0, double 0.0, 1 + %r2 = insertvalue %CGRect %r1, double %dw, 2 + %r3 = insertvalue %CGRect %r2, double %dh, 3 + call void @CGContextDrawImage(ptr %ctx, %CGRect %r3, ptr %img) + + call void @CGImageRelease(ptr %img) + call void @CGContextRelease(ptr %bmp) + call void @CGColorSpaceRelease(ptr %cs) + br label %out +out: + ret void +} + +; -acceptsFirstResponder — so the view receives key events +define internal i8 @ludic_yes(ptr %self, ptr %sel) { +entry: + ret i8 1 +} + +define void @win_open(i32 %w, i32 %h, i32 %scale, ptr %title) { +entry: + store i32 %w, ptr @W_fbw + store i32 %h, ptr @W_fbh + store i32 %scale, ptr @W_scale + + %appcls = call ptr @objc_getClass(ptr @.c_app) + %sel_sh = call ptr @sel_registerName(ptr @.s_shared) + %app = call ptr @objc_msgSend(ptr %appcls, ptr %sel_sh) + store ptr %app, ptr @W_app + %sel_pol = call ptr @sel_registerName(ptr @.s_policy) + %a1 = call ptr (ptr, ptr, i64) @objc_msgSend(ptr %app, ptr %sel_pol, i64 0) + + ; build the view class once: NSView + drawRect: + acceptsFirstResponder + %viewsuper = call ptr @objc_getClass(ptr @.c_view) + %cls = call ptr @objc_allocateClassPair(ptr %viewsuper, ptr @.c_ludic, i64 0) + %sel_draw = call ptr @sel_registerName(ptr @.s_drawr) + %m1 = call i8 @class_addMethod(ptr %cls, ptr %sel_draw, ptr @ludic_drawRect, ptr @.enc_draw) + %sel_afr = call ptr @sel_registerName(ptr @.s_afr) + %m2 = call i8 @class_addMethod(ptr %cls, ptr %sel_afr, ptr @ludic_yes, ptr @.enc_bool) + call void @objc_registerClassPair(ptr %cls) + + %wd = sitofp i32 %w to double + %hd = sitofp i32 %h to double + %scd = sitofp i32 %scale to double + %pw = fmul double %wd, %scd + %ph = fmul double %hd, %scd + %r0 = insertvalue %CGRect undef, double 0.0, 0 + %r1 = insertvalue %CGRect %r0, double 0.0, 1 + %r2 = insertvalue %CGRect %r1, double %pw, 2 + %rect = insertvalue %CGRect %r2, double %ph, 3 + + %wincls = call ptr @objc_getClass(ptr @.c_win) + %sel_alloc = call ptr @sel_registerName(ptr @.s_alloc) + %w0 = call ptr @objc_msgSend(ptr %wincls, ptr %sel_alloc) + %sel_initw = call ptr @sel_registerName(ptr @.s_initw) + ; NSWindowStyleMaskTitled|Closable = 3, NSBackingStoreBuffered = 2 + %win = call ptr (ptr, ptr, %CGRect, i64, i64, i8) @objc_msgSend(ptr %w0, ptr %sel_initw, %CGRect %rect, i64 3, i64 2, i8 0) + store ptr %win, ptr @W_win + + %strcls = call ptr @objc_getClass(ptr @.c_str) + %sel_utf8 = call ptr @sel_registerName(ptr @.s_utf8) + %nstitle = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %strcls, ptr %sel_utf8, ptr %title) + %sel_title = call ptr @sel_registerName(ptr @.s_title) + %a2 = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %win, ptr %sel_title, ptr %nstitle) + + %v0 = call ptr @objc_msgSend(ptr %cls, ptr %sel_alloc) + %sel_initf = call ptr @sel_registerName(ptr @.s_initf) + %view = call ptr (ptr, ptr, %CGRect) @objc_msgSend(ptr %v0, ptr %sel_initf, %CGRect %rect) + store ptr %view, ptr @W_view + %sel_setcv = call ptr @sel_registerName(ptr @.s_setcv) + %a3 = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %win, ptr %sel_setcv, ptr %view) + %sel_center = call ptr @sel_registerName(ptr @.s_center) + %a4 = call ptr @objc_msgSend(ptr %win, ptr %sel_center) + %sel_mkey = call ptr @sel_registerName(ptr @.s_mkey) + %a5 = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %win, ptr %sel_mkey, ptr null) + %sel_mfirst = call ptr @sel_registerName(ptr @.s_mfirst) + %a6 = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %win, ptr %sel_mfirst, ptr %view) + %sel_act = call ptr @sel_registerName(ptr @.s_act) + %a7 = call ptr (ptr, ptr, i8) @objc_msgSend(ptr %app, ptr %sel_act, i8 1) + ret void +} + +; Drain the event queue, remembering the last key pressed. Arrow keys map onto +; WASD and escape onto 'q', matching what the C backend did. +define i32 @win_poll() { +entry: + store i32 0, ptr @W_key + %app = load ptr, ptr @W_app + %none = icmp eq ptr %app, null + br i1 %none, label %done, label %setup +setup: + %sel_next = call ptr @sel_registerName(ptr @.s_next) + %sel_send = call ptr @sel_registerName(ptr @.s_send) + %sel_dp = call ptr @sel_registerName(ptr @.s_dpast) + %sel_type = call ptr @sel_registerName(ptr @.s_type) + %sel_kc = call ptr @sel_registerName(ptr @.s_keycd) + %sel_ch = call ptr @sel_registerName(ptr @.s_chars) + %sel_len = call ptr @sel_registerName(ptr @.s_length) + %sel_cat = call ptr @sel_registerName(ptr @.s_charat) + %sel_utf8 = call ptr @sel_registerName(ptr @.s_utf8) + %datecls = call ptr @objc_getClass(ptr @.c_date) + %strcls = call ptr @objc_getClass(ptr @.c_str) + %mode = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %strcls, ptr %sel_utf8, ptr @.mode) + br label %pump +pump: + %date = call ptr @objc_msgSend(ptr %datecls, ptr %sel_dp) + %ev = call ptr (ptr, ptr, i64, ptr, ptr, i8) @objc_msgSend(ptr %app, ptr %sel_next, i64 -1, ptr %date, ptr %mode, i8 1) + %got = icmp ne ptr %ev, null + br i1 %got, label %handle, label %finish +handle: + %ty = call i64 (ptr, ptr) @objc_msgSend(ptr %ev, ptr %sel_type) + %iskey = icmp eq i64 %ty, 10 ; NSEventTypeKeyDown + br i1 %iskey, label %key, label %forward +key: + %kc = call i16 (ptr, ptr) @objc_msgSend(ptr %ev, ptr %sel_kc) + %kc32 = zext i16 %kc to i32 + switch i32 %kc32, label %fromchars [ + i32 126, label %k_w + i32 125, label %k_s + i32 123, label %k_a + i32 124, label %k_d + i32 49, label %k_space + i32 36, label %k_ret + i32 53, label %k_esc + ] +k_w: store i32 119, ptr @W_key br label %forward +k_s: store i32 115, ptr @W_key br label %forward +k_a: store i32 97, ptr @W_key br label %forward +k_d: store i32 100, ptr @W_key br label %forward +k_space: store i32 32, ptr @W_key br label %forward +k_ret: store i32 10, ptr @W_key br label %forward +k_esc: + store i32 113, ptr @W_key + store i32 0, ptr @W_running + br label %forward +fromchars: + %chars = call ptr (ptr, ptr) @objc_msgSend(ptr %ev, ptr %sel_ch) + %clen = call i64 (ptr, ptr) @objc_msgSend(ptr %chars, ptr %sel_len) + %hasch = icmp sgt i64 %clen, 0 + br i1 %hasch, label %takechar, label %forward +takechar: + %ch = call i16 (ptr, ptr, i64) @objc_msgSend(ptr %chars, ptr %sel_cat, i64 0) + %ch32 = zext i16 %ch to i32 + store i32 %ch32, ptr @W_key + %isq = icmp eq i32 %ch32, 113 + br i1 %isq, label %quit, label %forward +quit: + store i32 0, ptr @W_running + br label %forward +forward: + %fwd = call ptr (ptr, ptr, ptr) @objc_msgSend(ptr %app, ptr %sel_send, ptr %ev) + br label %pump +finish: + ; a closed window ends the run + %win = load ptr, ptr @W_win + %hw = icmp ne ptr %win, null + br i1 %hw, label %checkvis, label %done +checkvis: + %sel_vis = call ptr @sel_registerName(ptr @.s_visib) + %vis = call i8 (ptr, ptr) @objc_msgSend(ptr %win, ptr %sel_vis) + %gone = icmp eq i8 %vis, 0 + br i1 %gone, label %closed, label %done +closed: + store i32 0, ptr @W_running + br label %done +done: + %k = load i32, ptr @W_key + ret i32 %k +} + +define void @win_present(ptr %fb, i32 %w, i32 %h) { +entry: + store ptr %fb, ptr @W_fb + store i32 %w, ptr @W_fbw + store i32 %h, ptr @W_fbh + %view = load ptr, ptr @W_view + %none = icmp eq ptr %view, null + br i1 %none, label %out, label %show +show: + %sel_disp = call ptr @sel_registerName(ptr @.s_disp) + %d = call ptr @objc_msgSend(ptr %view, ptr %sel_disp) + %u = call i32 @usleep(i32 16000) ; ~60 fps + br label %out +out: + ret void +} + +define i32 @win_running() { +entry: + %r = load i32, ptr @W_running + ret i32 %r +} + +define void @win_close() { +entry: + store i32 0, ptr @W_running + ret void +} diff --git a/runtime/native/core.ludic b/runtime/native/core.ludic new file mode 100644 index 00000000..b6f89c1f --- /dev/null +++ b/runtime/native/core.ludic @@ -0,0 +1,394 @@ +# ============================================================================ +# runtime/native/core.ludic — the Ludic runtime, written in Ludic. +# +# This is what the native backend links instead of a C runtime. Everything a +# game touches through a builtin — the framebuffer, rectangles, text, the +# registers, the RNG, input, the frame dump — is implemented right here in +# Ludic and compiled to machine code by ludicc like any other Ludic source. +# +# Underneath it there is exactly one layer, and it is not C: the compiler +# intrinsics (mem_alloc, peek8/poke8, peek32/poke32, file_open/file_write, +# read_byte, …) lower to direct calls into the platform's C ABI — malloc, +# fwrite, getchar. That ABI is the operating system's interface, the same floor +# Rust and Swift stand on. No C source is compiled at any point in the build. +# +# A builtin `clear(c)` in a game resolves to `rt_clear(c)` here; that is the +# whole protocol. Swap this file and you have swapped the runtime. +# +# This file is a fragment: ludicc splices it into every native build. It is not +# a `game`/`module` block of its own. +# ============================================================================ + +# ---- state ---------------------------------------------------------------- +var rt_fb: ptr = ptr_null() # framebuffer, one i32 (0x00RRGGBB) per pixel +var rt_fbw: int = 320 +var rt_fbh: int = 240 +var rt_regs: ptr = ptr_null() # the 64 general-purpose game registers +var rt_rng: int = 305419896 # xorshift32 state +var rt_alive: int = 1 # platform still running? + +# 5x7 glyphs for ASCII 32..90, 7 rows per glyph, each row a 5-bit mask stored +# biased by '0' so the whole font is one printable string literal. +fn rt_font() -> str { + return "00000004444404000000000000000000000IJ4:FC000000000000000000000000000000E>O>E0044O4400000448000O000000004012448@@>ACEIA>4<4444>>A168@ON11>11N26:BO22O@N11A>>@@NAA>O124888>AA>AA>>AA?11>04004000000000024842000O0O000842480>A164040000000>AAOAAANAANAAN>A@@@A>LBAAABLO@@L@@OO@@L@@@>A@GAA>AAAOAAA>44444>7222BBAAAAA>NAAN@@@>AAAEB=NAANDBA>A@>1A>O444444AAAAAA>AAAAA:4AAAEEKAAA:4:AAAA:4444O1248@O" +} + +fn rt_init() -> void { + rt_fb = mem_alloc(320 * 240 * 4) + rt_regs = mem_alloc(64 * 4) + mem_set(rt_regs, 0, 64 * 4) + rt_map = mem_alloc(96 * 64) + mem_set(rt_map, 32, 96 * 64) + rt_statusbuf = mem_alloc(96) + poke8(rt_statusbuf, 0, 0) + rt_image_init() + rt_tt_init() + rt_ui_init() + rt_clear(0) + if is_windowed() { + win_open(rt_fbw, rt_fbh, 3, game_title()) + } +} + +fn rt_shutdown() -> void { + if is_windowed() { + win_close() + return + } + rt_dump_ppm("out.ppm") +} + +# ---- framebuffer ---------------------------------------------------------- +fn rt_clear(c: int) -> void { + let n = rt_fbw * rt_fbh + for i in 0 .. n { + poke32(rt_fb, i, c) + } +} + +fn rt_put_px(x: int, y: int, c: int) -> void { + if x < 0 { return } + if y < 0 { return } + if x >= rt_fbw { return } + if y >= rt_fbh { return } + poke32(rt_fb, y * rt_fbw + x, c) +} + +fn rt_fill_rect(x: int, y: int, w: int, h: int, c: int) -> void { + let x0 = max(0, x) + let y0 = max(0, y) + let x1 = min(rt_fbw, x + w) + let y1 = min(rt_fbh, y + h) + let j = y0 + while j < y1 { + let row = j * rt_fbw + let i = x0 + while i < x1 { + poke32(rt_fb, row + i, c) + i = i + 1 + } + j = j + 1 + } +} + +fn rt_frame_rect(x: int, y: int, w: int, h: int, c: int) -> void { + rt_fill_rect(x, y, w, 1, c) + rt_fill_rect(x, y + h - 1, w, 1, c) + rt_fill_rect(x, y, 1, h, c) + rt_fill_rect(x + w - 1, y, 1, h, c) +} + +# Windowed: hand the framebuffer to the platform layer, which blits it into +# the view. Headless: nothing to do until shutdown writes the last frame out. +fn rt_present() -> void { + if is_windowed() { + win_present(rt_fb, rt_fbw, rt_fbh) + } +} + +# ---- text ----------------------------------------------------------------- +fn rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void { + let c = ch + if c >= 97 { + if c <= 122 { c = c - 32 } + } + if c < 32 { return } + if c > 90 { return } + let base = (c - 32) * 7 + let font = rt_font() + for row in 0 .. 7 { + let bits = peek8(font, base + row) - 48 + let b = bits + for cc in 0 .. 5 { + let on = b / 16 + if on == 1 { + rt_fill_rect(x + cc * sc, y + row * sc, sc, sc, colour) + } + b = (b - on * 16) * 2 + } + } +} + +fn rt_text(x: int, y: int, s: str, colour: int, sc: int) -> void { + let i = 0 + let cx = x + let ch = peek8(s, 0) + while ch != 0 { + rt_glyph(cx, y, ch, colour, sc) + cx = cx + 6 * sc + i = i + 1 + ch = peek8(s, i) + } +} + +fn rt_text_int(x: int, y: int, n: int, colour: int, sc: int) -> void { + if n == 0 { + rt_glyph(x, y, 48, colour, sc) + return + } + let v = n + let cx = x + if v < 0 { + rt_glyph(cx, y, 45, colour, sc) + cx = cx + 6 * sc + v = 0 - v + } + let digits = 0 + let t = v + while t > 0 { + digits = digits + 1 + t = t / 10 + } + let p = digits + while p > 0 { + let div = 1 + for k in 1 .. p { + div = div * 10 + } + rt_glyph(cx, y, 48 + (v / div) % 10, colour, sc) + cx = cx + 6 * sc + p = p - 1 + } +} + +# ---- registers ------------------------------------------------------------ +fn rt_reg(i: int) -> int { + if i < 0 { return 0 } + if i >= 64 { return 0 } + return peek32(rt_regs, i) +} + +fn rt_setreg(i: int, v: int) -> void { + if i < 0 { return } + if i >= 64 { return } + poke32(rt_regs, i, v) +} + +# ---- rng (xorshift32) ----------------------------------------------------- +fn rt_seed(s: int) -> void { + if s == 0 { + rt_rng = 305419896 + return + } + rt_rng = s +} + +# xorshift32 (Marsaglia). Runs on the raw 32-bit pattern, so the sign bit is +# masked off only when a caller asks for a number. +fn rt_next_rand() -> int { + let x = rt_rng + x = bxor(x, shl(x, 13)) + x = bxor(x, shr(x, 17)) + x = bxor(x, shl(x, 5)) + rt_rng = x + return band(x, 2147483647) +} + +fn rt_rng_range(lo: int, hi: int) -> int { + if hi <= lo { return lo } + return lo + rt_next_rand() % (hi - lo + 1) +} + +fn rt_rng_chance(pct: int) -> bool { + return rt_next_rand() % 100 < pct +} + +# ---- platform: input ------------------------------------------------------ +fn rt_poll() -> int { + if is_windowed() { + return win_poll() + } + let c = read_byte() + if c < 0 { + rt_alive = 0 + return 0 + } + if c == 113 { # 'q' quits, as in the headless C platform + rt_alive = 0 + } + return c +} + +fn rt_running() -> bool { + if is_windowed() { + return win_running() + } + return rt_alive +} + +# ---- writing the frame out ------------------------------------------------ +fn rt_put_str(buf: ptr, at: int, s: str) -> int { + let i = 0 + let n = at + let ch = peek8(s, 0) + while ch != 0 { + poke8(buf, n, ch) + n = n + 1 + i = i + 1 + ch = peek8(s, i) + } + return n +} + +fn rt_put_int(buf: ptr, at: int, v: int) -> int { + if v == 0 { + poke8(buf, at, 48) + return at + 1 + } + let digits = 0 + let t = v + while t > 0 { + digits = digits + 1 + t = t / 10 + } + let n = at + let p = digits + while p > 0 { + let div = 1 + for k in 1 .. p { + div = div * 10 + } + poke8(buf, n, 48 + (v / div) % 10) + n = n + 1 + p = p - 1 + } + return n +} + +fn rt_dump_ppm(path: str) -> void { + let f = file_open(path, "wb") + if ptr_is_null(f) { return } + + let hdr = mem_alloc(64) + let n = rt_put_str(hdr, 0, "P6\n") + n = rt_put_int(hdr, n, rt_fbw) + n = rt_put_str(hdr, n, " ") + n = rt_put_int(hdr, n, rt_fbh) + n = rt_put_str(hdr, n, "\n255\n") + file_write(f, hdr, n) + + let px = rt_fbw * rt_fbh + let buf = mem_alloc(px * 3) + for i in 0 .. px { + let c = peek32(rt_fb, i) + poke8(buf, i * 3, (c / 65536) % 256) + poke8(buf, i * 3 + 1, (c / 256) % 256) + poke8(buf, i * 3 + 2, c % 256) + } + file_write(f, buf, px * 3) + file_close(f) + mem_free(buf) + mem_free(hdr) +} + +import "inflate.ludic" +import "image.ludic" +import "truetype.ludic" +import "ui.ludic" + +# ---- tilemap -------------------------------------------------------------- +# A character grid the game paints with map_row() and reads with tile(). Stored +# as one byte per cell in a flat buffer; out-of-bounds reads answer '#' so a +# caller can treat the edge of the world as wall without special-casing it. +var rt_map: ptr = ptr_null() +var rt_mapw: int = 0 +var rt_maph: int = 0 + +fn rt_map_size(w: int, h: int) -> void { + rt_mapw = clamp(w, 0, 96) + rt_maph = clamp(h, 0, 64) + mem_set(rt_map, 32, 96 * 64) +} + +fn rt_map_row(y: int, s: str) -> void { + if y < 0 { return } + if y >= 64 { return } + let x = 0 + let ch = peek8(s, 0) + while ch != 0 { + if x >= 96 { return } + poke8(rt_map, y * 96 + x, ch) + x = x + 1 + ch = peek8(s, x) + } +} + +fn rt_tile(x: int, y: int) -> int { + if x < 0 { return 35 } + if y < 0 { return 35 } + if x >= rt_mapw { return 35 } + if y >= rt_maph { return 35 } + return peek8(rt_map, y * 96 + x) +} + +# ---- status line ---------------------------------------------------------- +# One persistent string of feedback/dialogue, copied into runtime-owned memory +# so it survives whatever the caller does with the original. +var rt_statusbuf: ptr = ptr_null() + +fn rt_status(s: str) -> void { + let i = 0 + let ch = peek8(s, 0) + while ch != 0 { + if i >= 95 { ch = 0 } + if ch != 0 { + poke8(rt_statusbuf, i, ch) + i = i + 1 + ch = peek8(s, i) + } + } + poke8(rt_statusbuf, i, 0) +} + +fn rt_status_text() -> ptr { + return rt_statusbuf +} + +# ---- snapshot: the runtime serialises its own half ------------------------ +# The compiler writes the ECS (entities, components, archetype kinds) because +# only it knows their shape. Everything below belongs to the runtime, so the +# runtime writes it — same order both ways. +fn rt_save_state(f: ptr) -> void { + let w = mem_alloc(16) + poke32(w, 0, rt_rng) + poke32(w, 1, rt_mapw) + poke32(w, 2, rt_maph) + poke32(w, 3, rt_alive) + file_write(f, w, 16) + file_write(f, rt_regs, 64 * 4) + file_write(f, rt_map, 96 * 64) + file_write(f, rt_statusbuf, 96) + mem_free(w) +} + +fn rt_load_state(f: ptr) -> void { + let w = mem_alloc(16) + file_read(f, w, 16) + rt_rng = peek32(w, 0) + rt_mapw = peek32(w, 1) + rt_maph = peek32(w, 2) + file_read(f, rt_regs, 64 * 4) + file_read(f, rt_map, 96 * 64) + file_read(f, rt_statusbuf, 96) + mem_free(w) +} diff --git a/runtime/native/image.ludic b/runtime/native/image.ludic new file mode 100644 index 00000000..15d23cd9 --- /dev/null +++ b/runtime/native/image.ludic @@ -0,0 +1,436 @@ +# ============================================================================ +# image.ludic — PNG decoding, images and sprites, written in Ludic. +# +# Replaces the C runtime's image half. Reads a real .png off disk, inflates the +# IDAT stream with the Ludic DEFLATE decoder next door, reverses the per-scanline +# filters, and expands whatever colour type the file uses into 0xAARRGGBB. +# +# Supported: 8/4/2/1-bit greyscale, 8-bit truecolour, indexed with PLTE/tRNS, +# greyscale+alpha and RGBA — the same set the C runtime handled. +# ============================================================================ + +const IMG_MAX: int = 32 +const SPR_MAX: int = 160 +const SPR_SZ: int = 16 + +var img_px: ptr = ptr_null() # IMG_MAX pointers to RGBA buffers +var img_w: ptr = ptr_null() +var img_h: ptr = ptr_null() +var img_n: int = 0 + +var spr_px: ptr = ptr_null() # SPR_MAX * 16 * 16 RGBA pixels, one block +var spr_n: int = 0 + +fn rt_image_init() -> void { + img_px = mem_alloc(IMG_MAX * 8) + img_w = mem_alloc(IMG_MAX * 4) + img_h = mem_alloc(IMG_MAX * 4) + spr_px = mem_alloc(SPR_MAX * SPR_SZ * SPR_SZ * 4) + mem_set(spr_px, 0, SPR_MAX * SPR_SZ * SPR_SZ * 4) +} + +# ---- decoding ------------------------------------------------------------- +fn png_be32(b: ptr, at: int) -> int { + return bor(bor(shl(peek8(b, at), 24), shl(peek8(b, at + 1), 16)), + bor(shl(peek8(b, at + 2), 8), peek8(b, at + 3))) +} + +fn png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool { + if peek8(b, at) != a { return false } + if peek8(b, at + 1) != c { return false } + if peek8(b, at + 2) != d { return false } + if peek8(b, at + 3) != e { return false } + return true +} + +fn rt_read_file(path: str) -> ptr { + let f = file_open(path, "rb") + if ptr_is_null(f) { return ptr_null() } + file_seek(f, 0, 2) + let n = file_tell(f) + file_seek(f, 0, 0) + if n <= 0 { file_close(f) return ptr_null() } + let buf = mem_alloc(n + 8) + file_read(f, buf, n) + file_close(f) + rt_file_len = n + return buf +} +var rt_file_len: int = 0 + +# decoded image is left in these; -1 width means failure +var png_w: int = 0 +var png_h: int = 0 +var png_px: ptr = ptr_null() + +fn rt_decode_png(path: str) -> bool { + png_w = 0 + png_h = 0 + png_px = ptr_null() + let d = rt_read_file(path) + if ptr_is_null(d) { return false } + let size = rt_file_len + if size < 8 { mem_free(d) return false } + if peek8(d, 0) != 137 { mem_free(d) return false } + if peek8(d, 1) != 80 { mem_free(d) return false } + + let w = 0 + let h = 0 + let bd = 0 + let ct = 0 + let plte = mem_alloc(768) + let trns = mem_alloc(256) + let ntrns = 0 + let idat = mem_alloc(size) + let idlen = 0 + let i = 8 + let done = 0 + + while done == 0 { + if i + 8 > size { done = 1 } + if done == 0 { + let ln = png_be32(d, i) + let typ = i + 4 + let body = i + 8 + if ln < 0 { done = 1 } + if body + ln > size { done = 1 } + if done == 0 { + if png_tag(d, typ, 73, 72, 68, 82) { # IHDR + w = png_be32(d, body) + h = png_be32(d, body + 4) + bd = peek8(d, body + 8) + ct = peek8(d, body + 9) + } + if png_tag(d, typ, 80, 76, 84, 69) { # PLTE + let m = min(ln, 768) + for k in 0 .. m { poke8(plte, k, peek8(d, body + k)) } + } + if png_tag(d, typ, 116, 82, 78, 83) { # tRNS + ntrns = min(ln, 256) + for k in 0 .. ntrns { poke8(trns, k, peek8(d, body + k)) } + } + if png_tag(d, typ, 73, 68, 65, 84) { # IDAT + for k in 0 .. ln { poke8(idat, idlen + k, peek8(d, body + k)) } + idlen = idlen + ln + } + if png_tag(d, typ, 73, 69, 78, 68) { done = 1 } # IEND + i = i + 12 + ln + } + } + } + + if w <= 0 { mem_free(d) return false } + if h <= 0 { mem_free(d) return false } + + let channels = 1 + if ct == 2 { channels = 3 } + if ct == 6 { channels = 4 } + if ct == 4 { channels = 2 } + let bppbits = bd * channels + let fbpp = (bppbits + 7) / 8 + if fbpp < 1 { fbpp = 1 } + let stride = (w * bppbits + 7) / 8 + let rawlen = h * (stride + 1) + let raw = mem_alloc(rawlen + 8) + if z_uncompress(idat, idlen, raw, rawlen) < 0 { + mem_free(d) mem_free(raw) mem_free(idat) + return false + } + + # reverse the per-scanline filters, in place + for y in 0 .. h { + let line = y * (stride + 1) + let ft = peek8(raw, line) + let cur = line + 1 + let prev = cur - (stride + 1) + for x in 0 .. stride { + let a = 0 + let b = 0 + let c = 0 + if x >= fbpp { a = peek8(raw, cur + x - fbpp) } + if y > 0 { b = peek8(raw, prev + x) } + if x >= fbpp { if y > 0 { c = peek8(raw, prev + x - fbpp) } } + let v = peek8(raw, cur + x) + if ft == 1 { v = v + a } + if ft == 2 { v = v + b } + if ft == 3 { v = v + (a + b) / 2 } + if ft == 4 { + let p = a + b - c + let pa = abs(p - a) + let pb = abs(p - b) + let pc = abs(p - c) + let pick = c + if pb <= pc { pick = b } + if pa <= pb { if pa <= pc { pick = a } } + v = v + pick + } + poke8(raw, cur + x, band(v, 255)) + } + } + + # expand to 0xAARRGGBB + let out = mem_alloc(w * h * 4) + let maxv = shl(1, bd) - 1 + for y in 0 .. h { + let row = y * (stride + 1) + 1 + for x in 0 .. w { + let R = 0 + let G = 0 + let B = 0 + let A = 255 + if ct == 6 { + R = peek8(raw, row + x * 4) + G = peek8(raw, row + x * 4 + 1) + B = peek8(raw, row + x * 4 + 2) + A = peek8(raw, row + x * 4 + 3) + } + if ct == 2 { + R = peek8(raw, row + x * 3) + G = peek8(raw, row + x * 3 + 1) + B = peek8(raw, row + x * 3 + 2) + } + if ct == 4 { + R = peek8(raw, row + x * 2) + G = R + B = R + A = peek8(raw, row + x * 2 + 1) + } + if ct == 3 { + let bp = x * bd + let idx = band(shr(peek8(raw, row + bp / 8), 8 - bd - bp % 8), maxv) + R = peek8(plte, idx * 3) + G = peek8(plte, idx * 3 + 1) + B = peek8(plte, idx * 3 + 2) + if idx < ntrns { A = peek8(trns, idx) } + } + if ct == 0 { + let bp = x * bd + let s = band(shr(peek8(raw, row + bp / 8), 8 - bd - bp % 8), maxv) + let g = s + if bd != 8 { g = s * 255 / maxv } + R = g + G = g + B = g + } + poke32(out, y * w + x, bor(bor(shl(A, 24), shl(R, 16)), bor(shl(G, 8), B))) + } + } + + mem_free(d) + mem_free(idat) + mem_free(raw) + mem_free(plte) + mem_free(trns) + png_w = w + png_h = h + png_px = out + return true +} + +# ---- images --------------------------------------------------------------- +fn rt_image_load(path: str) -> int { + if img_n >= IMG_MAX { return 0 - 1 } + if rt_decode_png(path) == false { return 0 - 1 } + let id = img_n + img_n = img_n + 1 + pokep(img_px, id, png_px) + poke32(img_w, id, png_w) + poke32(img_h, id, png_h) + return id +} + +fn rt_blend_px(x: int, y: int, argb: int) -> void { + let a = band(shr(argb, 24), 255) + if a == 0 { return } + if x < 0 { return } + if y < 0 { return } + if x >= rt_fbw { return } + if y >= rt_fbh { return } + let r = band(shr(argb, 16), 255) + let g = band(shr(argb, 8), 255) + let b = band(argb, 255) + if a != 255 { + let dst = peek32(rt_fb, y * rt_fbw + x) + let dr = band(shr(dst, 16), 255) + let dg = band(shr(dst, 8), 255) + let db = band(dst, 255) + r = (r * a + dr * (255 - a)) / 255 + g = (g * a + dg * (255 - a)) / 255 + b = (b * a + db * (255 - a)) / 255 + } + poke32(rt_fb, y * rt_fbw + x, bor(bor(shl(r, 16), shl(g, 8)), b)) +} + +fn rt_draw_image(id: int, dx: int, dy: int) -> void { + if id < 0 { return } + if id >= img_n { return } + let w = peek32(img_w, id) + let h = peek32(img_h, id) + let s = peekp(img_px, id) + for y in 0 .. h { + for x in 0 .. w { + rt_blend_px(dx + x, dy + y, peek32(s, y * w + x)) + } + } +} + +fn rt_draw_image_scaled(id: int, dx: int, dy: int, dw: int, dh: int) -> void { + if id < 0 { return } + if id >= img_n { return } + if dw <= 0 { return } + if dh <= 0 { return } + let w = peek32(img_w, id) + let h = peek32(img_h, id) + let s = peekp(img_px, id) + for y in 0 .. dh { + for x in 0 .. dw { + rt_blend_px(dx + x, dy + y, peek32(s, (y * h / dh) * w + x * w / dw)) + } + } +} + +# map one destination axis onto the source for a 9-slice: the two insets are +# copied 1:1 and only the middle stretches +fn rt_9map(d: int, dsz: int, ssz: int, inset: int) -> int { + if inset * 2 >= dsz { return d * ssz / max(dsz, 1) } + if inset * 2 >= ssz { return d * ssz / max(dsz, 1) } + if d < inset { return d } + if d >= dsz - inset { return ssz - (dsz - d) } + return inset + (d - inset) * (ssz - 2 * inset) / (dsz - 2 * inset) +} + +fn rt_draw_9slice(id: int, dx: int, dy: int, dw: int, dh: int, inset: int) -> void { + if id < 0 { return } + if id >= img_n { return } + if dw <= 0 { return } + if dh <= 0 { return } + let w = peek32(img_w, id) + let h = peek32(img_h, id) + let s = peekp(img_px, id) + for y in 0 .. dh { + let sy = rt_9map(y, dh, h, inset) + for x in 0 .. dw { + rt_blend_px(dx + x, dy + y, peek32(s, sy * w + rt_9map(x, dw, w, inset))) + } + } +} + +# ---- sprites (16x16 art) -------------------------------------------------- +fn rt_load_png(path: str) -> int { + if spr_n >= SPR_MAX { return 0 - 1 } + if rt_decode_png(path) == false { return 0 - 1 } + let id = spr_n + spr_n = spr_n + 1 + let base = id * SPR_SZ * SPR_SZ + for y in 0 .. SPR_SZ { + for x in 0 .. SPR_SZ { + let px = 0 + if x < png_w { + if y < png_h { + let c = peek32(png_px, y * png_w + x) + if band(shr(c, 24), 255) >= 128 { px = bor(shl(255, 24), band(c, 16777215)) } + } + } + poke32(spr_px, base + y * SPR_SZ + x, px) + } + } + mem_free(png_px) + png_px = ptr_null() + return id +} + +fn rt_draw_sprite(id: int, px: int, py: int) -> void { + if id < 0 { return } + if id >= spr_n { return } + let base = id * SPR_SZ * SPR_SZ + for y in 0 .. SPR_SZ { + for x in 0 .. SPR_SZ { + let p = peek32(spr_px, base + y * SPR_SZ + x) + if band(shr(p, 24), 255) != 0 { + rt_put_px(px + x, py + y, band(p, 16777215)) + } + } + } +} + +fn rt_draw_sprite_scaled(id: int, px: int, py: int, sc: int) -> void { + if id < 0 { return } + if id >= spr_n { return } + if sc < 1 { return } + let base = id * SPR_SZ * SPR_SZ + for y in 0 .. SPR_SZ { + for x in 0 .. SPR_SZ { + let p = peek32(spr_px, base + y * SPR_SZ + x) + if band(shr(p, 24), 255) != 0 { + rt_fill_rect(px + x * sc, py + y * sc, sc, sc, band(p, 16777215)) + } + } + } +} + +# ---- .lspr sprite sheets (palette + ASCII rows) --------------------------- +fn rt_hexval(c: int) -> int { + if c >= 48 { if c <= 57 { return c - 48 } } + if c >= 97 { if c <= 102 { return c - 87 } } + if c >= 65 { if c <= 70 { return c - 55 } } + return 0 - 1 +} + +fn rt_load_sprites(path: str) -> void { + let d = rt_read_file(path) + if ptr_is_null(d) { spr_n = 0 return } + let size = rt_file_len + let pal = mem_alloc(128 * 4) + mem_set(pal, 0, 128 * 4) + let cur = 0 - 1 + let row = 0 + let i = 0 + while i < size { + let start = i + let len = 0 + let j = start + while j < size { + let ch = peek8(d, j) + if ch == 10 { j = size } else { len = len + 1 j = j + 1 } + } + let c0 = peek8(d, start) + if c0 == 112 { # 'p' — "pal " + let ch = peek8(d, start + 4) + let v = 0 + for k in 0 .. 6 { + let hv = rt_hexval(peek8(d, start + 6 + k)) + if hv >= 0 { v = v * 16 + hv } + } + if ch < 128 { poke32(pal, ch, bor(shl(255, 24), v)) } + } + if c0 == 115 { # 's' — "spr" starts a new sprite + cur = 0 - 1 + if spr_n < SPR_MAX { + cur = spr_n + spr_n = spr_n + 1 + mem_set(ptr_add(spr_px, cur * SPR_SZ * SPR_SZ * 4), 0, SPR_SZ * SPR_SZ * 4) + } + row = 0 + } + if c0 != 112 { + if c0 != 115 { + if c0 != 35 { # '#' comment + if cur >= 0 { + if row < SPR_SZ { + for x in 0 .. SPR_SZ { + if x < len { + poke32(spr_px, cur * SPR_SZ * SPR_SZ + row * SPR_SZ + x, + peek32(pal, band(peek8(d, start + x), 127))) + } + } + row = row + 1 + } + } + } + } + } + i = start + len + 1 + } + mem_free(pal) + mem_free(d) +} diff --git a/runtime/native/inflate.ludic b/runtime/native/inflate.ludic new file mode 100644 index 00000000..8a6108fa --- /dev/null +++ b/runtime/native/inflate.ludic @@ -0,0 +1,276 @@ +# ============================================================================ +# inflate.ludic — DEFLATE decompression (RFC 1951), written in Ludic. +# +# PNG stores its pixels zlib-compressed, so decoding one means implementing +# inflate. The C runtime linked zlib for this. We don't: zlib is not present by +# default on every target Ludic compiles for (Windows especially), and shipping +# a dependency to read a sprite is a poor trade when the algorithm is this +# small. So it lives here, in the language. +# +# The decoder is the canonical-Huffman formulation from Mark Adler's `puff`: +# a symbol table plus per-length counts, walked one bit at a time. Slower than +# a lookup-table decoder, and entirely fast enough to load sprites at startup. +# ============================================================================ + +# ---- bit reader (DEFLATE packs bits least-significant-first) --------------- +var z_src: ptr = ptr_null() +var z_len: int = 0 +var z_pos: int = 0 +var z_bitbuf: int = 0 +var z_bitcnt: int = 0 +var z_err: int = 0 + +fn z_start(src: ptr, len: int) -> void { + z_src = src + z_len = len + z_pos = 0 + z_bitbuf = 0 + z_bitcnt = 0 + z_err = 0 +} + +fn z_bits(need: int) -> int { + let val = z_bitbuf + while z_bitcnt < need { + if z_pos >= z_len { + z_err = 1 + return 0 + } + val = bor(val, shl(peek8(z_src, z_pos), z_bitcnt)) + z_pos = z_pos + 1 + z_bitcnt = z_bitcnt + 8 + } + z_bitbuf = shr(val, need) + z_bitcnt = z_bitcnt - need + return band(val, shl(1, need) - 1) +} + +# ---- Huffman tables ------------------------------------------------------- +# A table is a single buffer: 16 length-counts followed by the symbols in +# canonical order. One allocation, no structs. +fn z_table_new(nsym: int) -> ptr { + return mem_alloc((16 + nsym) * 4) +} + +# lengths[i] = code length of symbol i (0 = symbol unused) +fn z_table_build(table: ptr, lengths: ptr, n: int) -> void { + for i in 0 .. 16 { + poke32(table, i, 0) + } + for s in 0 .. n { + let l = peek32(lengths, s) + poke32(table, l, peek32(table, l) + 1) + } + poke32(table, 0, 0) # length 0 means "not present" + # offset of each length's first symbol + let offs = mem_alloc(16 * 4) + poke32(offs, 1, 0) + for l in 1 .. 15 { + poke32(offs, l + 1, peek32(offs, l) + peek32(table, l)) + } + for s in 0 .. n { + let l = peek32(lengths, s) + if l != 0 { + poke32(table, 16 + peek32(offs, l), s) + poke32(offs, l, peek32(offs, l) + 1) + } + } + mem_free(offs) +} + +fn z_decode(table: ptr) -> int { + let code = 0 + let first = 0 + let index = 0 + for len in 1 .. 16 { + code = bor(code, z_bits(1)) + let count = peek32(table, len) + if code - first < count { + return peek32(table, 16 + index + (code - first)) + } + index = index + count + first = shl(first + count, 1) + code = shl(code, 1) + } + z_err = 1 + return -1 +} + +# ---- length / distance code tables (RFC 1951 section 3.2.5) --------------- +fn z_len_base(sym: int) -> int { + if sym < 8 { return 3 + sym } + if sym == 28 { return 258 } + let extra = (sym - 4) / 4 + let group = shl(1, extra) + return 3 + shl(group - 1, 2) + 4 + (sym - 4 - extra * 4) * group +} + +fn z_len_extra(sym: int) -> int { + if sym < 8 { return 0 } + if sym == 28 { return 0 } + return (sym - 4) / 4 +} + +fn z_dist_base(sym: int) -> int { + if sym < 4 { return 1 + sym } + let extra = (sym - 2) / 2 + let group = shl(1, extra) + return 1 + shl(group, 1) + (sym - 2 - extra * 2) * group +} + +fn z_dist_extra(sym: int) -> int { + if sym < 4 { return 0 } + return (sym - 2) / 2 +} + +# ---- block decoders ------------------------------------------------------- +# `out` is the destination window; returns the new write position, or -1. +fn z_stored(out: ptr, at: int, cap: int) -> int { + z_bitbuf = 0 + z_bitcnt = 0 # stored blocks are byte-aligned + if z_pos + 4 > z_len { return -1 } + let n = peek8(z_src, z_pos) + shl(peek8(z_src, z_pos + 1), 8) + z_pos = z_pos + 4 # LEN then its one's complement + let w = at + for i in 0 .. n { + if z_pos >= z_len { return -1 } + if w >= cap { return -1 } + poke8(out, w, peek8(z_src, z_pos)) + w = w + 1 + z_pos = z_pos + 1 + } + return w +} + +fn z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int { + let w = at + let sym = z_decode(lit) + while sym != 256 { + if z_err != 0 { return -1 } + if sym < 0 { return -1 } + if sym < 256 { + if w >= cap { return -1 } + poke8(out, w, sym) + w = w + 1 + } + if sym > 256 { + let s = sym - 257 + if s >= 29 { return -1 } + let length = z_len_base(s) + z_bits(z_len_extra(s)) + let d = z_decode(dist) + if d < 0 { return -1 } + let distance = z_dist_base(d) + z_bits(z_dist_extra(d)) + if distance > w { return -1 } + for k in 0 .. length { + if w >= cap { return -1 } + poke8(out, w, peek8(out, w - distance)) + w = w + 1 + } + } + sym = z_decode(lit) + } + return w +} + +fn z_fixed_tables(lit: ptr, dist: ptr) -> void { + let lengths = mem_alloc(288 * 4) + for i in 0 .. 144 { poke32(lengths, i, 8) } + for i in 144 .. 256 { poke32(lengths, i, 9) } + for i in 256 .. 280 { poke32(lengths, i, 7) } + for i in 280 .. 288 { poke32(lengths, i, 8) } + z_table_build(lit, lengths, 288) + for i in 0 .. 30 { poke32(lengths, i, 5) } + z_table_build(dist, lengths, 30) + mem_free(lengths) +} + +fn z_dynamic_tables(lit: ptr, dist: ptr) -> int { + let nlen = z_bits(5) + 257 + let ndist = z_bits(5) + 1 + let ncode = z_bits(4) + 4 + if nlen > 286 { return 0 } + if ndist > 30 { return 0 } + + let lengths = mem_alloc(320 * 4) + for i in 0 .. 19 { poke32(lengths, i, 0) } + # the code-length alphabet is transmitted in this fixed permutation + # 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 — biased by '0' so it is one literal + let order = "@AB08796:5;4<3=2>1?" + for i in 0 .. ncode { + poke32(lengths, peek8(order, i) - 48, z_bits(3)) + } + let clen = z_table_new(19) + z_table_build(clen, lengths, 19) + + let n = 0 + while n < nlen + ndist { + let sym = z_decode(clen) + if sym < 0 { return 0 } + if sym < 16 { + poke32(lengths, n, sym) + n = n + 1 + } + if sym >= 16 { + let prev = 0 + let rep = 0 + if sym == 16 { + if n == 0 { return 0 } + prev = peek32(lengths, n - 1) + rep = 3 + z_bits(2) + } + if sym == 17 { rep = 3 + z_bits(3) } + if sym == 18 { rep = 11 + z_bits(7) } + for k in 0 .. rep { + if n < 320 { + poke32(lengths, n, prev) + n = n + 1 + } + } + } + } + z_table_build(lit, lengths, nlen) + # the distance lengths follow the literal ones in the same buffer + let dl = mem_alloc(32 * 4) + for i in 0 .. ndist { poke32(dl, i, peek32(lengths, nlen + i)) } + z_table_build(dist, dl, ndist) + mem_free(dl) + mem_free(lengths) + mem_free(clen) + return 1 +} + +# Inflate a raw DEFLATE stream. Returns bytes written, or -1. +fn z_inflate(src: ptr, len: int, out: ptr, cap: int) -> int { + z_start(src, len) + let lit = z_table_new(288) + let dist = z_table_new(30) + let w = 0 + let final = 0 + while final == 0 { + final = z_bits(1) + let btype = z_bits(2) + if z_err != 0 { return -1 } + if btype == 0 { w = z_stored(out, w, cap) } + if btype == 1 { + z_fixed_tables(lit, dist) + w = z_codes(out, w, cap, lit, dist) + } + if btype == 2 { + if z_dynamic_tables(lit, dist) == 0 { return -1 } + w = z_codes(out, w, cap, lit, dist) + } + if btype == 3 { return -1 } + if w < 0 { return -1 } + } + mem_free(lit) + mem_free(dist) + return w +} + +# zlib wrapper (RFC 1950): two header bytes, then DEFLATE, then Adler-32. +fn z_uncompress(src: ptr, len: int, out: ptr, cap: int) -> int { + if len < 2 { return -1 } + let cmf = peek8(src, 0) + if band(cmf, 15) != 8 { return -1 } + return z_inflate(ptr_add(src, 2), len - 2, out, cap) +} diff --git a/runtime/native/truetype.ludic b/runtime/native/truetype.ludic new file mode 100644 index 00000000..3d29f2c6 --- /dev/null +++ b/runtime/native/truetype.ludic @@ -0,0 +1,428 @@ +# ============================================================================ +# truetype.ludic — a TrueType font loader and glyph rasterizer, in Ludic. +# +# Parses the sfnt container, maps codepoints through cmap (formats 0/4/6/12), +# decodes simple and composite `glyf` outlines, flattens the quadratic Béziers, +# and fills them with the nonzero winding rule at 4x4 supersampling to get an +# 8-bit coverage mask. Then a glyph cache and a UTF-8 text layer on top. +# +# The C original used floats. Ludic has Q16.16 `fixed`, which is enough: at 16 +# fractional bits a glyph coordinate is exact to 1/65536 of a pixel, far below +# the 1/4-pixel supersample grid the rasterizer actually quantises to. +# ============================================================================ + +const TT_MAX: int = 8 # fonts loaded at once +const TT_SS: int = 4 # supersample factor per axis +const TT_PTS: int = 4096 # points in one outline +const TT_EDGES: int = 16384 # line segments in one glyph +const TT_GC: int = 512 # glyph cache entries + +# ---- per-font tables (parallel arrays; index = font id) ------------------- +var tt_data: ptr = ptr_null() +var tt_size: ptr = ptr_null() +var tt_upem: ptr = ptr_null() +var tt_nglyf: ptr = ptr_null() +var tt_locfm: ptr = ptr_null() +var tt_nhm: ptr = ptr_null() +var tt_asc: ptr = ptr_null() +var tt_desc: ptr = ptr_null() +var tt_gap: ptr = ptr_null() +var tt_glyf: ptr = ptr_null() +var tt_loca: ptr = ptr_null() +var tt_hmtx: ptr = ptr_null() +var tt_cmap: ptr = ptr_null() +var tt_cfmt: ptr = ptr_null() +var tt_n: int = 0 + +# ---- outline + edge scratch (reused for every glyph) ---------------------- +var ol_x: ptr = ptr_null() +var ol_y: ptr = ptr_null() +var ol_on: ptr = ptr_null() +var ol_ends: ptr = ptr_null() +var ol_n: int = 0 +var ol_ne: int = 0 + +var ed_x0: ptr = ptr_null() +var ed_y0: ptr = ptr_null() +var ed_x1: ptr = ptr_null() +var ed_y1: ptr = ptr_null() +var ed_n: int = 0 + +var sc_x: ptr = ptr_null() # scanline crossings +var sc_d: ptr = ptr_null() + +# ---- glyph cache ---------------------------------------------------------- +var gc_used: ptr = ptr_null() +var gc_font: ptr = ptr_null() +var gc_cp: ptr = ptr_null() +var gc_px: ptr = ptr_null() +var gc_w: ptr = ptr_null() +var gc_h: ptr = ptr_null() +var gc_ox: ptr = ptr_null() +var gc_oy: ptr = ptr_null() +var gc_adv: ptr = ptr_null() +var gc_bmp: ptr = ptr_null() + +fn rt_tt_init() -> void { + tt_data = mem_alloc(TT_MAX * 8) + tt_size = mem_alloc(TT_MAX * 4) + tt_upem = mem_alloc(TT_MAX * 4) + tt_nglyf = mem_alloc(TT_MAX * 4) + tt_locfm = mem_alloc(TT_MAX * 4) + tt_nhm = mem_alloc(TT_MAX * 4) + tt_asc = mem_alloc(TT_MAX * 4) + tt_desc = mem_alloc(TT_MAX * 4) + tt_gap = mem_alloc(TT_MAX * 4) + tt_glyf = mem_alloc(TT_MAX * 4) + tt_loca = mem_alloc(TT_MAX * 4) + tt_hmtx = mem_alloc(TT_MAX * 4) + tt_cmap = mem_alloc(TT_MAX * 4) + tt_cfmt = mem_alloc(TT_MAX * 4) + + ol_x = mem_alloc(TT_PTS * 4) + ol_y = mem_alloc(TT_PTS * 4) + ol_on = mem_alloc(TT_PTS * 4) + ol_ends = mem_alloc(256 * 4) + + ed_x0 = mem_alloc(TT_EDGES * 4) + ed_y0 = mem_alloc(TT_EDGES * 4) + ed_x1 = mem_alloc(TT_EDGES * 4) + ed_y1 = mem_alloc(TT_EDGES * 4) + sc_x = mem_alloc(TT_EDGES * 4) + sc_d = mem_alloc(TT_EDGES * 4) + + gc_used = mem_alloc(TT_GC * 4) + gc_font = mem_alloc(TT_GC * 4) + gc_cp = mem_alloc(TT_GC * 4) + gc_px = mem_alloc(TT_GC * 4) + gc_w = mem_alloc(TT_GC * 4) + gc_h = mem_alloc(TT_GC * 4) + gc_ox = mem_alloc(TT_GC * 4) + gc_oy = mem_alloc(TT_GC * 4) + gc_adv = mem_alloc(TT_GC * 4) + gc_bmp = mem_alloc(TT_GC * 8) + mem_set(gc_used, 0, TT_GC * 4) +} + +# ---- big-endian readers --------------------------------------------------- +fn tt_u16(d: ptr, at: int) -> int { + return bor(shl(peek8(d, at), 8), peek8(d, at + 1)) +} +fn tt_i16(d: ptr, at: int) -> int { + let v = tt_u16(d, at) + if v >= 32768 { return v - 65536 } + return v +} +fn tt_u32(d: ptr, at: int) -> int { + return bor(bor(shl(peek8(d, at), 24), shl(peek8(d, at + 1), 16)), + bor(shl(peek8(d, at + 2), 8), peek8(d, at + 3))) +} +fn tt_i8(d: ptr, at: int) -> int { + let v = peek8(d, at) + if v >= 128 { return v - 256 } + return v +} + +fn tt_find_table(d: ptr, base: int, a: int, b: int, c: int, e: int) -> int { + let n = tt_u16(d, base + 4) + for i in 0 .. n { + let rec = base + 12 + i * 16 + if peek8(d, rec) == a { + if peek8(d, rec + 1) == b { + if peek8(d, rec + 2) == c { + if peek8(d, rec + 3) == e { return tt_u32(d, rec + 8) } + } + } + } + } + return 0 - 1 +} + +# pick the most capable Unicode subtable, as the C loader did +fn tt_pick_cmap(id: int, d: ptr, co: int) -> void { + poke32(tt_cmap, id, 0 - 1) + poke32(tt_cfmt, id, 0) + if co < 0 { return } + let n = tt_u16(d, co + 2) + let best = 0 - 1 + let bestscore = 0 - 1 + for i in 0 .. n { + let rec = co + 4 + i * 8 + let plat = tt_u16(d, rec) + let enc = tt_u16(d, rec + 2) + let off = tt_u32(d, rec + 4) + let score = 0 - 1 + if plat == 0 { score = 2 } + if plat == 0 { if enc == 4 { score = 4 } } + if plat == 0 { if enc == 6 { score = 4 } } + if plat == 3 { if enc == 1 { score = 3 } } + if plat == 3 { if enc == 10 { score = 5 } } + if score > bestscore { + bestscore = score + best = co + off + } + } + if best < 0 { return } + poke32(tt_cmap, id, best) + poke32(tt_cfmt, id, tt_u16(d, best)) +} + +fn rt_font_load(path: str) -> int { + if tt_n >= TT_MAX { return 0 - 1 } + let d = rt_read_file(path) + if ptr_is_null(d) { return 0 - 1 } + let size = rt_file_len + let base = 0 + # a .ttc collection points at its first font + if size >= 16 { + if peek8(d, 0) == 116 { if peek8(d, 1) == 116 { if peek8(d, 2) == 99 { if peek8(d, 3) == 102 { + base = tt_u32(d, 12) + } } } } + } + let head = tt_find_table(d, base, 104, 101, 97, 100) + let maxp = tt_find_table(d, base, 109, 97, 120, 112) + let hhea = tt_find_table(d, base, 104, 104, 101, 97) + let loca = tt_find_table(d, base, 108, 111, 99, 97) + let glyf = tt_find_table(d, base, 103, 108, 121, 102) + let hmtx = tt_find_table(d, base, 104, 109, 116, 120) + if head < 0 { return 0 - 1 } + if maxp < 0 { return 0 - 1 } + if hhea < 0 { return 0 - 1 } + if loca < 0 { return 0 - 1 } + if glyf < 0 { return 0 - 1 } + if hmtx < 0 { return 0 - 1 } + + let id = tt_n + tt_n = tt_n + 1 + pokep(tt_data, id, d) + poke32(tt_size, id, size) + let upem = tt_u16(d, head + 18) + if upem <= 0 { upem = 1000 } + poke32(tt_upem, id, upem) + poke32(tt_locfm, id, tt_i16(d, head + 50)) + poke32(tt_nglyf, id, tt_u16(d, maxp + 4)) + poke32(tt_asc, id, tt_i16(d, hhea + 4)) + poke32(tt_desc, id, tt_i16(d, hhea + 6)) + poke32(tt_gap, id, tt_i16(d, hhea + 8)) + poke32(tt_nhm, id, tt_u16(d, hhea + 34)) + poke32(tt_glyf, id, glyf) + poke32(tt_loca, id, loca) + poke32(tt_hmtx, id, hmtx) + tt_pick_cmap(id, d, tt_find_table(d, base, 99, 109, 97, 112)) + return id +} + +# ---- codepoint -> glyph id ------------------------------------------------ +fn tt_glyph_index(id: int, cp: int) -> int { + let d = peekp(tt_data, id) + let s = peek32(tt_cmap, id) + if s < 0 { return 0 } + let fmt = peek32(tt_cfmt, id) + + if fmt == 4 { + if cp > 65535 { return 0 } + let segX2 = tt_u16(d, s + 6) + let segc = segX2 / 2 + let endp = s + 14 + let startp = endp + segX2 + 2 + let deltap = startp + segX2 + let rangep = deltap + segX2 + for i in 0 .. segc { + if cp <= tt_u16(d, endp + i * 2) { + let st = tt_u16(d, startp + i * 2) + if cp < st { return 0 } + let ro = tt_u16(d, rangep + i * 2) + if ro == 0 { return band(cp + tt_i16(d, deltap + i * 2), 65535) } + let g = tt_u16(d, rangep + i * 2 + ro + (cp - st) * 2) + if g == 0 { return 0 } + return band(g + tt_i16(d, deltap + i * 2), 65535) + } + } + return 0 + } + if fmt == 12 { + let ng = tt_u32(d, s + 12) + for i in 0 .. ng { + let g = s + 16 + i * 12 + if cp >= tt_u32(d, g) { + if cp <= tt_u32(d, g + 4) { return tt_u32(d, g + 8) + (cp - tt_u32(d, g)) } + } + } + return 0 + } + if fmt == 6 { + let first = tt_u16(d, s + 6) + let cnt = tt_u16(d, s + 8) + if cp >= first { if cp < first + cnt { return tt_u16(d, s + 10 + (cp - first) * 2) } } + return 0 + } + if fmt == 0 { + if cp < 256 { return peek8(d, s + 6 + cp) } + } + return 0 +} + +fn tt_advance(id: int, gid: int) -> int { + let d = peekp(tt_data, id) + let hmtx = peek32(tt_hmtx, id) + let n = peek32(tt_nhm, id) + if gid < n { return tt_u16(d, hmtx + gid * 4) } + return tt_u16(d, hmtx + (n - 1) * 4) +} + +# ---- outline extraction --------------------------------------------------- +fn ol_pt(x: fixed, y: fixed, on: int) -> void { + if ol_n >= TT_PTS { return } + pokef(ol_x, ol_n, x) + pokef(ol_y, ol_n, y) + poke32(ol_on, ol_n, on) + ol_n = ol_n + 1 +} + +fn tt_glyph_start(id: int, gid: int) -> int { + let d = peekp(tt_data, id) + let loca = peek32(tt_loca, id) + if peek32(tt_locfm, id) == 0 { return tt_u16(d, loca + gid * 2) * 2 } + return tt_u32(d, loca + gid * 4) +} +fn tt_glyph_end(id: int, gid: int) -> int { + let d = peekp(tt_data, id) + let loca = peek32(tt_loca, id) + if peek32(tt_locfm, id) == 0 { return tt_u16(d, loca + (gid + 1) * 2) * 2 } + return tt_u32(d, loca + (gid + 1) * 4) +} + +# Append glyph `gid`, transformed by [a b c e] + (dx,dy), to the outline. +fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx: fixed, dy: fixed, depth: int) -> void { + if gid < 0 { return } + if gid >= peek32(tt_nglyf, id) { return } + if depth > 5 { return } + let goff = tt_glyph_start(id, gid) + let gend = tt_glyph_end(id, gid) + if goff >= gend { return } + let d = peekp(tt_data, id) + let g = peek32(tt_glyf, id) + goff + let nc = tt_i16(d, g) + + if nc >= 0 { + let endpts = g + 10 + let npts = 0 + if nc > 0 { npts = tt_u16(d, endpts + (nc - 1) * 2) + 1 } + let p = endpts + nc * 2 + p = p + 2 + tt_u16(d, p) # skip instructions + + let flags = mem_alloc(npts + 8) + let i = 0 + while i < npts { + let fl = peek8(d, p) + p = p + 1 + poke8(flags, i, fl) + i = i + 1 + if band(fl, 8) != 0 { # REPEAT + let r = peek8(d, p) + p = p + 1 + while r > 0 { + if i < npts { poke8(flags, i, fl) i = i + 1 } + r = r - 1 + } + } + } + + let xs = mem_alloc((npts + 1) * 4) + let ys = mem_alloc((npts + 1) * 4) + let xv = 0 + for k in 0 .. npts { + let fl = peek8(flags, k) + if band(fl, 2) != 0 { + let dxv = peek8(d, p) + p = p + 1 + if band(fl, 16) != 0 { xv = xv + dxv } else { xv = xv - dxv } + } else { + if band(fl, 16) == 0 { xv = xv + tt_i16(d, p) p = p + 2 } + } + poke32(xs, k, xv) + } + let yv = 0 + for k in 0 .. npts { + let fl = peek8(flags, k) + if band(fl, 4) != 0 { + let dyv = peek8(d, p) + p = p + 1 + if band(fl, 32) != 0 { yv = yv + dyv } else { yv = yv - dyv } + } else { + if band(fl, 32) == 0 { yv = yv + tt_i16(d, p) p = p + 2 } + } + poke32(ys, k, yv) + } + + let start = 0 + for ci in 0 .. nc { + let last = tt_u16(d, endpts + ci * 2) + for k in start .. last + 1 { + let X = fx(peek32(xs, k)) + let Y = fx(peek32(ys, k)) + ol_pt(a * X + c * Y + dx, b * X + e * Y + dy, band(peek8(flags, k), 1)) + } + if ol_ne < 256 { + poke32(ol_ends, ol_ne, ol_n) + ol_ne = ol_ne + 1 + } + start = last + 1 + } + mem_free(flags) + mem_free(xs) + mem_free(ys) + } else { + # composite glyph: components, each with its own placement and transform + let p = g + 10 + let more = 1 + while more == 1 { + let flags = tt_u16(d, p) + let cgid = tt_u16(d, p + 2) + p = p + 4 + let arg1 = 0 + let arg2 = 0 + if band(flags, 1) != 0 { + arg1 = tt_i16(d, p) + arg2 = tt_i16(d, p + 2) + p = p + 4 + } else { + arg1 = tt_i8(d, p) + arg2 = tt_i8(d, p + 1) + p = p + 2 + } + let ca = 1.0 + let cb = 0.0 + let cc = 0.0 + let ce = 1.0 + if band(flags, 8) != 0 { + ca = as_fixed(shl(tt_i16(d, p), 2)) # F2Dot14 -> Q16.16 + ce = ca + p = p + 2 + } + if band(flags, 64) != 0 { + ca = as_fixed(shl(tt_i16(d, p), 2)) + ce = as_fixed(shl(tt_i16(d, p + 2), 2)) + p = p + 4 + } + if band(flags, 128) != 0 { + ca = as_fixed(shl(tt_i16(d, p), 2)) + cb = as_fixed(shl(tt_i16(d, p + 2), 2)) + cc = as_fixed(shl(tt_i16(d, p + 4), 2)) + ce = as_fixed(shl(tt_i16(d, p + 6), 2)) + p = p + 8 + } + let odx = dx + let ody = dy + if band(flags, 2) != 0 { + odx = a * fx(arg1) + c * fx(arg2) + dx + ody = b * fx(arg1) + e * fx(arg2) + dy + } + tt_load_outline(id, cgid, a * ca + c * cb, b * ca + e * cb, a * cc + c * ce, b * cc + e * ce, odx, ody, depth + 1) + more = 0 + if band(flags, 32) != 0 { more = 1 } + } + } +} + +import "truetype_raster.ludic" diff --git a/runtime/native/truetype_raster.ludic b/runtime/native/truetype_raster.ludic new file mode 100644 index 00000000..25c10363 --- /dev/null +++ b/runtime/native/truetype_raster.ludic @@ -0,0 +1,380 @@ +# truetype_raster.ludic — glyph rasterization, the glyph cache, UTF-8 decoding +# and text drawing. Split out of truetype.ludic (the sfnt/cmap/outline half). + +# ---- rasterization -------------------------------------------------------- +fn ed_add(x0: fixed, y0: fixed, x1: fixed, y1: fixed) -> void { + if ed_n >= TT_EDGES { return } + pokef(ed_x0, ed_n, x0) + pokef(ed_y0, ed_n, y0) + pokef(ed_x1, ed_n, x1) + pokef(ed_y1, ed_n, y1) + ed_n = ed_n + 1 +} + +fn tt_isqrt(v: int) -> int { + if v <= 0 { return 0 } + let r = 0 + let b = 32768 + while b > 0 { + let t = r + b + if t * t <= v { r = t } + b = b / 2 + } + return r +} + +# flatten one quadratic Bézier into line segments, subdivided by chord length +fn ed_quad(x0: fixed, y0: fixed, cx: fixed, cy: fixed, x1: fixed, y1: fixed) -> void { + let dx = flr(x1) - flr(x0) + let dy = flr(y1) - flr(y0) + let n = tt_isqrt(dx * dx + dy * dy) / 3 + if n < 2 { n = 2 } + if n > 24 { n = 24 } + let px = x0 + let py = y0 + for i in 1 .. n + 1 { + let t = fx(i) / n + let u = 1.0 - t + let qx = u * u * x0 + 2.0 * u * t * cx + t * t * x1 + let qy = u * u * y0 + 2.0 * u * t * cy + t * t * y1 + ed_add(px, py, qx, qy) + px = qx + py = qy + } +} + +# Rasterize a glyph at `px` pixels. Coverage lands in a fresh buffer; the +# geometry is left in gr_* for the caller. +var gr_w: int = 0 +var gr_h: int = 0 +var gr_ox: int = 0 +var gr_oy: int = 0 +var gr_adv: int = 0 + +fn tt_raster(id: int, gid: int, px: int) -> ptr { + let upem = peek32(tt_upem, id) + let scale = fx(px) / upem + gr_adv = flr(fx(tt_advance(id, gid)) * scale + 0.5) + gr_w = 0 + gr_h = 0 + ol_n = 0 + ol_ne = 0 + ed_n = 0 + tt_load_outline(id, gid, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0) + if ol_n == 0 { return ptr_null() } + + let minx = 999999.0 + let miny = 999999.0 + let maxx = 0.0 - 999999.0 + let maxy = 0.0 - 999999.0 + for i in 0 .. ol_n { + let X = peekf(ol_x, i) * scale + let Y = peekf(ol_y, i) * scale + if X < minx { minx = X } + if X > maxx { maxx = X } + if Y < miny { miny = Y } + if Y > maxy { maxy = Y } + } + let x0 = flr(minx) + let y0 = flr(miny) + let x1 = flr(maxx) + 1 + let y1 = flr(maxy) + 1 + if maxx == fx(flr(maxx)) { x1 = flr(maxx) } + if maxy == fx(flr(maxy)) { y1 = flr(maxy) } + let W = x1 - x0 + let H = y1 - y0 + if W <= 0 { return ptr_null() } + if H <= 0 { return ptr_null() } + if W > 1024 { return ptr_null() } + if H > 1024 { return ptr_null() } + gr_w = W + gr_h = H + gr_ox = x0 + gr_oy = y1 + + # build edges in supersample space (y grows downward) + let start = 0 + for ci in 0 .. ol_ne { + let end = peek32(ol_ends, ci) + let cnt = end - start + if cnt >= 2 { + let first_on = 0 - 1 + for i in 0 .. cnt { + if first_on < 0 { if peek32(ol_on, start + i) == 1 { first_on = i } } + } + let sx = 0.0 + let sy = 0.0 + if first_on < 0 { + # all off-curve: start at the midpoint of the first and last point + let mx = (peekf(ol_x, start) + peekf(ol_x, start + cnt - 1)) / 2 + let my = (peekf(ol_y, start) + peekf(ol_y, start + cnt - 1)) / 2 + sx = (mx * scale - fx(x0)) * TT_SS + sy = (fx(y1) - my * scale) * TT_SS + first_on = 0 + } else { + sx = (peekf(ol_x, start + first_on) * scale - fx(x0)) * TT_SS + sy = (fx(y1) - peekf(ol_y, start + first_on) * scale) * TT_SS + } + let curx = sx + let cury = sy + let step = 0 + while step < cnt { + let i = (first_on + 1 + step) % cnt + let ix = (peekf(ol_x, start + i) * scale - fx(x0)) * TT_SS + let iy = (fx(y1) - peekf(ol_y, start + i) * scale) * TT_SS + if peek32(ol_on, start + i) == 1 { + ed_add(curx, cury, ix, iy) + curx = ix + cury = iy + } else { + let j = (i + 1) % cnt + let jx = (peekf(ol_x, start + j) * scale - fx(x0)) * TT_SS + let jy = (fx(y1) - peekf(ol_y, start + j) * scale) * TT_SS + let ex = jx + let ey = jy + if peek32(ol_on, start + j) == 1 { + step = step + 1 + } else { + ex = (ix + jx) / 2 # implied on-curve midpoint + ey = (iy + jy) / 2 + } + ed_quad(curx, cury, ix, iy, ex, ey) + curx = ex + cury = ey + } + step = step + 1 + } + ed_add(curx, cury, sx, sy) + } + start = end + } + + let SW = W * TT_SS + let SH = H * TT_SS + let cover = mem_alloc(W * H) + mem_set(cover, 0, W * H) + let unit = 255 / (TT_SS * TT_SS) + + for sy in 0 .. SH { + let yc = fx(sy) + 0.5 + let m = 0 + for i in 0 .. ed_n { + let ya = peekf(ed_y0, i) + let yb = peekf(ed_y1, i) + let hit = 0 + if ya <= yc { if yb > yc { hit = 1 } } + if yb <= yc { if ya > yc { hit = 1 } } + if hit == 1 { + let t = (yc - ya) / (yb - ya) + pokef(sc_x, m, peekf(ed_x0, i) + t * (peekf(ed_x1, i) - peekf(ed_x0, i))) + if yb > ya { poke32(sc_d, m, 1) } else { poke32(sc_d, m, 0 - 1) } + m = m + 1 + } + } + # insertion sort the crossings by x + for i in 1 .. m { + let kx = peekf(sc_x, i) + let kd = peek32(sc_d, i) + let j = i - 1 + let placed = 0 + while j >= 0 { + if peekf(sc_x, j) > kx { + pokef(sc_x, j + 1, peekf(sc_x, j)) + poke32(sc_d, j + 1, peek32(sc_d, j)) + j = j - 1 + } else { + pokef(sc_x, j + 1, kx) + poke32(sc_d, j + 1, kd) + placed = 1 + j = 0 - 1 + } + } + if placed == 0 { + pokef(sc_x, 0, kx) + poke32(sc_d, 0, kd) + } + } + let wind = 0 + let oy = sy / TT_SS + for i in 0 .. m - 1 { + wind = wind + peek32(sc_d, i) + if wind != 0 { + let xa = peekf(sc_x, i) + let xb = peekf(sc_x, i + 1) + if xa < 0.0 { xa = 0.0 } + if xb > fx(SW) { xb = fx(SW) } + if xb > xa { + let ixa = flr(xa) + let ixb = flr(xb) + 1 + for sx in ixa .. ixb { + let cxl = xa + let cxr = xb + if fx(sx) > cxl { cxl = fx(sx) } + if fx(sx + 1) < cxr { cxr = fx(sx + 1) } + let cvr = cxr - cxl + if cvr > 0.0 { + let oxp = sx / TT_SS + if oxp >= 0 { if oxp < W { if oy >= 0 { if oy < H { + let v = peek8(cover, oy * W + oxp) + flr(cvr * unit) + if v > 255 { v = 255 } + poke8(cover, oy * W + oxp, v) + } } } } + } + } + } + } + } + } + return cover +} + +# ---- glyph cache ---------------------------------------------------------- +# Rasterizing is far too slow to repeat per frame, so a coverage mask is kept +# per (font, codepoint, size). Open addressing, 8 probes, evict on miss. +fn gc_hash(font: int, cp: int, px: int) -> int { + return band(bxor(bxor(cp * 2654435761, shl(font, 20)), shl(px, 8)), TT_GC - 1) +} + +fn tt_glyph_get(font: int, cp: int, px: int) -> int { + let h = gc_hash(font, cp, px) + for k in 0 .. 8 { + let s = band(h + k, TT_GC - 1) + if peek32(gc_used, s) == 1 { + if peek32(gc_font, s) == font { + if peek32(gc_cp, s) == cp { + if peek32(gc_px, s) == px { return s } + } + } + } + } + let s = h + if peek32(gc_used, s) == 1 { + let old = peekp(gc_bmp, s) + if ptr_is_null(old) == false { mem_free(old) } + } + let bmp = tt_raster(font, tt_glyph_index(font, cp), px) + pokep(gc_bmp, s, bmp) + poke32(gc_used, s, 1) + poke32(gc_font, s, font) + poke32(gc_cp, s, cp) + poke32(gc_px, s, px) + poke32(gc_w, s, gr_w) + poke32(gc_h, s, gr_h) + poke32(gc_ox, s, gr_ox) + poke32(gc_oy, s, gr_oy) + poke32(gc_adv, s, gr_adv) + return s +} + +# ---- UTF-8 ---------------------------------------------------------------- +var u8_next: int = 0 # byte index just past the codepoint last decoded + +fn tt_utf8(s: str, at: int) -> int { + let c = peek8(s, at) + let extra = 0 - 1 + if c < 128 { extra = 0 } + if shr(c, 5) == 6 { extra = 1 } + if shr(c, 4) == 14 { extra = 2 } + if shr(c, 3) == 30 { extra = 3 } + if extra < 0 { + u8_next = at + 1 + return 65533 + } + if extra == 0 { + u8_next = at + 1 + return c + } + let cp = band(c, shr(63, extra)) + for i in 0 .. extra { + let b = peek8(s, at + 1 + i) + if band(b, 192) != 128 { + u8_next = at + 1 + i + return 65533 + } + cp = bor(shl(cp, 6), band(b, 63)) + } + u8_next = at + 1 + extra + return cp +} + +# ---- drawing -------------------------------------------------------------- +fn tt_blit(bmp: ptr, w: int, h: int, dx: int, dy: int, colour: int) -> void { + if ptr_is_null(bmp) { return } + let cr = band(shr(colour, 16), 255) + let cg = band(shr(colour, 8), 255) + let cb = band(colour, 255) + for y in 0 .. h { + let py = dy + y + if py >= 0 { + if py < rt_fbh { + for x in 0 .. w { + let a = peek8(bmp, y * w + x) + if a != 0 { + let pxx = dx + x + if pxx >= 0 { + if pxx < rt_fbw { + let d = peek32(rt_fb, py * rt_fbw + pxx) + let rr = (cr * a + band(shr(d, 16), 255) * (255 - a)) / 255 + let rg = (cg * a + band(shr(d, 8), 255) * (255 - a)) / 255 + let rb = (cb * a + band(d, 255) * (255 - a)) / 255 + poke32(rt_fb, py * rt_fbw + pxx, bor(bor(shl(rr, 16), shl(rg, 8)), rb)) + } + } + } + } + } + } + } +} + +fn rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) -> void { + if font < 0 { return } + if font >= tt_n { return } + if px <= 0 { return } + let upem = peek32(tt_upem, font) + let scale = fx(px) / upem + let baseline = y + flr(fx(peek32(tt_asc, font)) * scale + 0.5) + let lineh = flr(fx(peek32(tt_asc, font) - peek32(tt_desc, font) + peek32(tt_gap, font)) * scale + 0.5) + let penx = x + let i = 0 + while peek8(s, i) != 0 { + let cp = tt_utf8(s, i) + i = u8_next + if cp == 10 { + penx = x + baseline = baseline + lineh + } else { + let g = tt_glyph_get(font, cp, px) + tt_blit(peekp(gc_bmp, g), peek32(gc_w, g), peek32(gc_h, g), penx + peek32(gc_ox, g), baseline - peek32(gc_oy, g), colour) + penx = penx + peek32(gc_adv, g) + } + } +} + +fn rt_text_w(font: int, s: str, px: int) -> int { + if font < 0 { return 0 } + if font >= tt_n { return 0 } + if px <= 0 { return 0 } + let w = 0 + let best = 0 + let i = 0 + while peek8(s, i) != 0 { + let cp = tt_utf8(s, i) + i = u8_next + if cp == 10 { + if w > best { best = w } + w = 0 + } else { + w = w + peek32(gc_adv, tt_glyph_get(font, cp, px)) + } + } + if w > best { best = w } + return best +} + +fn rt_text_h(font: int, px: int) -> int { + if font < 0 { return 0 } + if font >= tt_n { return 0 } + let scale = fx(px) / peek32(tt_upem, font) + return flr(fx(peek32(tt_asc, font) - peek32(tt_desc, font) + peek32(tt_gap, font)) * scale + 0.5) +} diff --git a/runtime/native/ui.ludic b/runtime/native/ui.ludic new file mode 100644 index 00000000..0d2bef01 --- /dev/null +++ b/runtime/native/ui.ludic @@ -0,0 +1,312 @@ +# ============================================================================ +# ui.ludic — the retained UI engine, written in Ludic. +# +# A `ui Name { … }` block in a game is DATA: the compiler flattens the widget +# tree and emits a build function that calls rt_ui_set() for each property. +# Everything after that — measure/arrange layout, 9-slice skins, text, keyboard +# focus and activation — is this file. +# +# Widgets are parallel arrays rather than a struct per widget, because Ludic +# has components for per-entity data and raw memory for everything else, and a +# widget is not an entity. +# ============================================================================ + +const UI_MAX: int = 256 + +# widget types, matching the compiler's flattener +const WT_PANEL: int = 0 +const WT_COL: int = 1 +const WT_ROW: int = 2 +const WT_LABEL: int = 3 +const WT_BUTTON: int = 4 +const WT_IMAGE: int = 5 +const WT_SPACER: int = 6 + +# property keys — the private protocol between ludicc and this runtime +const K_TYPE: int = 0 +const K_PARENT: int = 1 +const K_W: int = 2 +const K_H: int = 3 +const K_X: int = 4 +const K_Y: int = 5 +const K_HASPOS: int = 6 +const K_PAD: int = 7 +const K_GAP: int = 8 +const K_BG: int = 9 +const K_FG: int = 10 +const K_BORDER: int = 11 +const K_ALIGN: int = 12 +const K_GROW: int = 13 +const K_FONT: int = 14 +const K_SIZE: int = 15 +const K_SKININSET: int = 16 +const K_FOCUSABLE: int = 17 +const K_VISIBLE: int = 18 +const K_IMG: int = 19 +const K_SKIN: int = 20 + +var ui_type: ptr = ptr_null() +var ui_parent: ptr = ptr_null() +var ui_w: ptr = ptr_null() +var ui_h: ptr = ptr_null() +var ui_x: ptr = ptr_null() +var ui_y: ptr = ptr_null() +var ui_haspos: ptr = ptr_null() +var ui_pad: ptr = ptr_null() +var ui_gap: ptr = ptr_null() +var ui_bg: ptr = ptr_null() +var ui_fg: ptr = ptr_null() +var ui_border: ptr = ptr_null() +var ui_align: ptr = ptr_null() +var ui_grow: ptr = ptr_null() +var ui_font: ptr = ptr_null() +var ui_size: ptr = ptr_null() +var ui_skin: ptr = ptr_null() +var ui_inset: ptr = ptr_null() +var ui_img: ptr = ptr_null() +var ui_focusable: ptr = ptr_null() +var ui_rx: ptr = ptr_null() +var ui_ry: ptr = ptr_null() +var ui_rw: ptr = ptr_null() +var ui_rh: ptr = ptr_null() +var ui_visible: ptr = ptr_null() +var ui_fired: ptr = ptr_null() +var ui_hasdyn: ptr = ptr_null() +var ui_dyn: ptr = ptr_null() # UI_MAX * 96 bytes +var ui_text: ptr = ptr_null() # UI_MAX static string pointers + +var ui_n: int = 0 +var ui_active: int = -1 +var ui_focus: int = -1 + +fn rt_ui_init() -> void { + ui_type = mem_alloc(UI_MAX * 4) + ui_parent = mem_alloc(UI_MAX * 4) + ui_w = mem_alloc(UI_MAX * 4) + ui_h = mem_alloc(UI_MAX * 4) + ui_x = mem_alloc(UI_MAX * 4) + ui_y = mem_alloc(UI_MAX * 4) + ui_haspos = mem_alloc(UI_MAX * 4) + ui_pad = mem_alloc(UI_MAX * 4) + ui_gap = mem_alloc(UI_MAX * 4) + ui_bg = mem_alloc(UI_MAX * 4) + ui_fg = mem_alloc(UI_MAX * 4) + ui_border = mem_alloc(UI_MAX * 4) + ui_align = mem_alloc(UI_MAX * 4) + ui_grow = mem_alloc(UI_MAX * 4) + ui_font = mem_alloc(UI_MAX * 4) + ui_size = mem_alloc(UI_MAX * 4) + ui_skin = mem_alloc(UI_MAX * 4) + ui_inset = mem_alloc(UI_MAX * 4) + ui_img = mem_alloc(UI_MAX * 4) + ui_focusable = mem_alloc(UI_MAX * 4) + ui_rx = mem_alloc(UI_MAX * 4) + ui_ry = mem_alloc(UI_MAX * 4) + ui_rw = mem_alloc(UI_MAX * 4) + ui_rh = mem_alloc(UI_MAX * 4) + ui_visible = mem_alloc(UI_MAX * 4) + ui_fired = mem_alloc(UI_MAX * 4) + ui_hasdyn = mem_alloc(UI_MAX * 4) + ui_dyn = mem_alloc(UI_MAX * 96) + ui_text = mem_alloc(UI_MAX * 8) +} + +# ---- build-time interface (called by compiler-emitted code) --------------- +fn rt_ui_reset(n: int) -> void { + ui_n = n + for i in 0 .. n { + poke32(ui_type, i, 0) + poke32(ui_parent, i, 0 - 1) + poke32(ui_w, i, 0) + poke32(ui_h, i, 0) + poke32(ui_x, i, 0) + poke32(ui_y, i, 0) + poke32(ui_haspos, i, 0) + poke32(ui_pad, i, 0) + poke32(ui_gap, i, 0) + poke32(ui_bg, i, 0 - 1) + poke32(ui_fg, i, 0 - 1) + poke32(ui_border, i, 0 - 1) + poke32(ui_align, i, 0 - 1) + poke32(ui_grow, i, 0) + poke32(ui_font, i, 0 - 1) + poke32(ui_size, i, 8) + poke32(ui_skin, i, 0 - 1) + poke32(ui_inset, i, 6) + poke32(ui_img, i, 0 - 1) + poke32(ui_focusable, i, 0) + poke32(ui_visible, i, 1) + poke32(ui_fired, i, 0) + poke32(ui_hasdyn, i, 0) + pokep(ui_text, i, ptr_null()) + } +} + +fn rt_ui_set(i: int, k: int, v: int) -> void { + if i < 0 { return } + if i >= UI_MAX { return } + if k == K_TYPE { poke32(ui_type, i, v) } + if k == K_PARENT { poke32(ui_parent, i, v) } + if k == K_W { poke32(ui_w, i, v) } + if k == K_H { poke32(ui_h, i, v) } + if k == K_X { poke32(ui_x, i, v) } + if k == K_Y { poke32(ui_y, i, v) } + if k == K_HASPOS { poke32(ui_haspos, i, v) } + if k == K_PAD { poke32(ui_pad, i, v) } + if k == K_GAP { poke32(ui_gap, i, v) } + if k == K_BG { poke32(ui_bg, i, v) } + if k == K_FG { poke32(ui_fg, i, v) } + if k == K_BORDER { poke32(ui_border, i, v) } + if k == K_ALIGN { poke32(ui_align, i, v) } + if k == K_GROW { poke32(ui_grow, i, v) } + if k == K_FONT { poke32(ui_font, i, v) } + if k == K_SIZE { poke32(ui_size, i, v) } + if k == K_SKININSET { poke32(ui_inset, i, v) } + if k == K_FOCUSABLE { poke32(ui_focusable, i, v) } + if k == K_VISIBLE { poke32(ui_visible, i, v) } + if k == K_IMG { poke32(ui_img, i, v) } + if k == K_SKIN { poke32(ui_skin, i, v) } +} + +fn rt_ui_static_text(i: int, s: str) -> void { + if i < 0 { return } + if i >= UI_MAX { return } + pokep(ui_text, i, s) +} + +# ---- text helpers: TrueType when a font is loaded, bitmap otherwise ------- +fn ui_str(i: int) -> ptr { + if peek32(ui_hasdyn, i) == 1 { return ptr_add(ui_dyn, i * 96) } + let t = peekp(ui_text, i) + if ptr_is_null(t) { return ptr_add(ui_dyn, i * 96) } + return t +} + +fn ui_draw_text(font: int, x: int, y: int, s: ptr, colour: int, size: int) -> void { + if font >= 0 { + if font < tt_n { + rt_text_ttf(font, x, y, s, colour, size) + return + } + } + rt_text(x, y, s, colour, max(size / 8, 1)) +} + +fn ui_tw(font: int, s: ptr, size: int) -> int { + if font >= 0 { + if font < tt_n { return rt_text_w(font, s, size) } + } + let n = 0 + while peek8(s, n) != 0 { n = n + 1 } + return n * 6 * max(size / 8, 1) +} + +fn ui_th(font: int, size: int) -> int { + if font >= 0 { + if font < tt_n { return rt_text_h(font, size) } + } + return 7 * max(size / 8, 1) +} + +fn ui_is_container(t: int) -> bool { + if t == WT_PANEL { return true } + if t == WT_COL { return true } + if t == WT_ROW { return true } + return false +} +fn ui_dir(t: int) -> int { + if t == WT_ROW { return 0 } + return 1 +} +fn ui_under(i: int, root: int) -> bool { + let k = i + while k >= 0 { + if k == root { return true } + k = peek32(ui_parent, k) + } + return false +} + +# ---- measure: content sizes, children before parents ---------------------- +fn ui_measure() -> void { + let i = ui_n - 1 + while i >= 0 { + if peek32(ui_visible, i) == 0 { + poke32(ui_rw, i, 0) + poke32(ui_rh, i, 0) + } else { + let t = peek32(ui_type, i) + let pad = peek32(ui_pad, i) + let cw = 0 + let ch = 0 + if t == WT_LABEL { cw = 0 - 1 } + if t == WT_BUTTON { cw = 0 - 1 } + if cw == 0 - 1 { + let s = ui_str(i) + cw = ui_tw(peek32(ui_font, i), s, peek32(ui_size, i)) + 2 * pad + ch = ui_th(peek32(ui_font, i), peek32(ui_size, i)) + 2 * pad + if t == WT_BUTTON { + cw = cw + 10 + ch = ch + 6 + } + } else { + if t == WT_IMAGE { + let im = peek32(ui_img, i) + if im >= 0 { + cw = peek32(img_w, im) + ch = peek32(img_h, im) + } + } else { + if t == WT_SPACER { + cw = peek32(ui_w, i) + ch = peek32(ui_h, i) + } else { + let dir = ui_dir(t) + let mainsz = 0 + let cross = 0 + let nc = 0 + for c in 0 .. ui_n { + if peek32(ui_parent, c) == i { + if peek32(ui_visible, c) == 1 { + if dir == 1 { + mainsz = mainsz + peek32(ui_rh, c) + cross = max(cross, peek32(ui_rw, c)) + } else { + mainsz = mainsz + peek32(ui_rw, c) + cross = max(cross, peek32(ui_rh, c)) + } + nc = nc + 1 + } + } + } + if nc > 1 { mainsz = mainsz + peek32(ui_gap, i) * (nc - 1) } + mainsz = mainsz + 2 * pad + cross = cross + 2 * pad + if dir == 1 { + cw = cross + ch = mainsz + } else { + cw = mainsz + ch = cross + } + } + } + } + let rw = peek32(ui_w, i) + let rh = peek32(ui_h, i) + if rw == 0 { rw = cw } + if rh == 0 { rh = ch } + poke32(ui_rw, i, rw) + poke32(ui_rh, i, rh) + } + i = i - 1 + } +} + +fn ui_eff_align(child: int, parent: int) -> int { + if peek32(ui_align, child) >= 0 { return peek32(ui_align, child) } + if peek32(ui_align, parent) >= 0 { return peek32(ui_align, parent) } + return 0 +} + +import "ui_draw.ludic" diff --git a/runtime/native/ui_draw.ludic b/runtime/native/ui_draw.ludic new file mode 100644 index 00000000..a7032264 --- /dev/null +++ b/runtime/native/ui_draw.ludic @@ -0,0 +1,283 @@ +# ui_draw.ludic — layout arrange, drawing, focus/activation and the game-facing +# accessors. Split out of ui.ludic (the storage/build/measure half). + +# ---- arrange: rects, parents before children ------------------------------ +fn ui_arrange(i: int, x: int, y: int) -> void { + poke32(ui_rx, i, x) + poke32(ui_ry, i, y) + let t = peek32(ui_type, i) + if ui_is_container(t) == false { return } + let dir = ui_dir(t) + let pad = peek32(ui_pad, i) + let gap = peek32(ui_gap, i) + let innerw = peek32(ui_rw, i) - 2 * pad + let innerh = peek32(ui_rh, i) - 2 * pad + let total = 0 + let ng = 0 + let grows = 0 + for c in 0 .. ui_n { + if peek32(ui_parent, c) == i { + if peek32(ui_visible, c) == 1 { + if dir == 1 { total = total + peek32(ui_rh, c) } else { total = total + peek32(ui_rw, c) } + ng = ng + 1 + grows = grows + peek32(ui_grow, c) + } + } + } + if ng > 1 { total = total + gap * (ng - 1) } + let avail = innerw + if dir == 1 { avail = innerh } + let extra = max(avail - total, 0) + let cx = x + pad + let cy = y + pad + for c in 0 .. ui_n { + if peek32(ui_parent, c) == i { + if peek32(ui_visible, c) == 1 { + let kw = peek32(ui_rw, c) + let kh = peek32(ui_rh, c) + if peek32(ui_grow, c) != 0 { + if grows > 0 { + if dir == 1 { kh = kh + extra / grows } else { kw = kw + extra / grows } + } + } + let al = ui_eff_align(c, i) + poke32(ui_rw, c, kw) + poke32(ui_rh, c, kh) + if dir == 1 { + let ax = x + pad + if al == 1 { ax = x + pad + (innerw - kw) / 2 } + if al == 2 { ax = x + pad + (innerw - kw) } + ui_arrange(c, ax, cy) + cy = cy + kh + gap + } else { + let ay = y + pad + if al == 1 { ay = y + pad + (innerh - kh) / 2 } + if al == 2 { ay = y + pad + (innerh - kh) } + ui_arrange(c, cx, ay) + cx = cx + kw + gap + } + } + } + } +} + +fn ui_layout() -> void { + if ui_active < 0 { return } + ui_measure() + let px = (rt_fbw - peek32(ui_rw, ui_active)) / 2 + let py = (rt_fbh - peek32(ui_rh, ui_active)) / 2 + if peek32(ui_haspos, ui_active) == 1 { + px = peek32(ui_x, ui_active) + py = peek32(ui_y, ui_active) + } + ui_arrange(ui_active, px, py) +} + +# ---- drawing -------------------------------------------------------------- +fn ui_lighten(c: int) -> int { + let r = band(shr(c, 16), 255) + let g = band(shr(c, 8), 255) + let b = band(c, 255) + r = r + (255 - r) * 4 / 10 + g = g + (255 - g) * 4 / 10 + b = b + (255 - b) * 4 / 10 + return bor(bor(shl(r, 16), shl(g, 8)), b) +} + +fn ui_draw_node(i: int) -> void { + if peek32(ui_visible, i) == 0 { return } + let t = peek32(ui_type, i) + let rx = peek32(ui_rx, i) + let ry = peek32(ui_ry, i) + let rw = peek32(ui_rw, i) + let rh = peek32(ui_rh, i) + let skin = peek32(ui_skin, i) + let focused = 0 + if i == ui_focus { focused = 1 } + + if t == WT_PANEL { + if skin >= 0 { + rt_draw_9slice(skin, rx, ry, rw, rh, peek32(ui_inset, i)) + } else { + if peek32(ui_bg, i) >= 0 { rt_fill_rect(rx, ry, rw, rh, peek32(ui_bg, i)) } + if peek32(ui_border, i) >= 0 { rt_frame_rect(rx, ry, rw, rh, peek32(ui_border, i)) } + } + } + if t == WT_BUTTON { + let bg = peek32(ui_bg, i) + if bg < 0 { bg = 0x2a2a3a } + if focused == 1 { bg = ui_lighten(bg) } + if skin >= 0 { + rt_draw_9slice(skin, rx, ry, rw, rh, peek32(ui_inset, i)) + } else { + rt_fill_rect(rx, ry, rw, rh, bg) + } + let bc = peek32(ui_border, i) + if bc < 0 { bc = 0x555577 } + if focused == 1 { bc = 0xffff00 } + rt_frame_rect(rx, ry, rw, rh, bc) + let s = ui_str(i) + let fg = peek32(ui_fg, i) + if fg < 0 { fg = 0xffffff } + let font = peek32(ui_font, i) + let size = peek32(ui_size, i) + ui_draw_text(font, rx + (rw - ui_tw(font, s, size)) / 2, ry + (rh - ui_th(font, size)) / 2, s, fg, size) + } + if t == WT_LABEL { + let s = ui_str(i) + let fg = peek32(ui_fg, i) + if fg < 0 { fg = 0xffffff } + let font = peek32(ui_font, i) + let size = peek32(ui_size, i) + let pad = peek32(ui_pad, i) + let tw = ui_tw(font, s, size) + let tx = rx + pad + let al = peek32(ui_align, i) + if al == 1 { tx = rx + (rw - tw) / 2 } + if al == 2 { tx = rx + rw - pad - tw } + ui_draw_text(font, tx, ry + pad, s, fg, size) + } + if t == WT_IMAGE { + if peek32(ui_img, i) >= 0 { rt_draw_image_scaled(peek32(ui_img, i), rx, ry, rw, rh) } + } + for c in 0 .. ui_n { + if peek32(ui_parent, c) == i { ui_draw_node(c) } + } +} + +# ---- focus and activation ------------------------------------------------- +var ui_fl: ptr = ptr_null() + +fn ui_focusables() -> int { + if ptr_is_null(ui_fl) { ui_fl = mem_alloc(UI_MAX * 4) } + let n = 0 + for i in 0 .. ui_n { + if peek32(ui_focusable, i) == 1 { + if peek32(ui_visible, i) == 1 { + if ui_under(i, ui_active) { + poke32(ui_fl, n, i) + n = n + 1 + } + } + } + } + return n +} + +fn rt_ui_open(root: int) -> void { + ui_active = root + let n = ui_focusables() + ui_focus = 0 - 1 + if n > 0 { ui_focus = peek32(ui_fl, 0) } +} + +fn rt_ui_tick(k: int) -> void { + if ui_active < 0 { return } + for i in 0 .. ui_n { poke32(ui_fired, i, 0) } + ui_layout() + let n = ui_focusables() + if n == 0 { + ui_focus = 0 - 1 + return + } + let cur = 0 - 1 + for i in 0 .. n { + if peek32(ui_fl, i) == ui_focus { cur = i } + } + if cur < 0 { + cur = 0 + ui_focus = peek32(ui_fl, 0) + } + if k == 119 { # 'w' + cur = (cur - 1 + n) % n + ui_focus = peek32(ui_fl, cur) + } + if k == 115 { # 's' + cur = (cur + 1) % n + ui_focus = peek32(ui_fl, cur) + } + if k == 32 { poke32(ui_fired, ui_focus, 1) } + if k == 10 { poke32(ui_fired, ui_focus, 1) } + if k == 13 { poke32(ui_fired, ui_focus, 1) } +} + +fn rt_ui_render() -> void { + if ui_active < 0 { return } + ui_layout() + ui_draw_node(ui_active) +} + +# ---- game-facing accessors ------------------------------------------------ +fn rt_ui_clicked(id: int) -> bool { + if id < 0 { return false } + if id >= ui_n { return false } + return peek32(ui_fired, id) == 1 +} + +fn rt_ui_set_text(id: int, s: str) -> void { + if id < 0 { return } + if id >= ui_n { return } + let base = id * 96 + let i = 0 + let ch = peek8(s, 0) + while ch != 0 { + if i >= 95 { ch = 0 } + if ch != 0 { + poke8(ui_dyn, base + i, ch) + i = i + 1 + ch = peek8(s, i) + } + } + poke8(ui_dyn, base + i, 0) + poke32(ui_hasdyn, id, 1) +} + +fn rt_ui_set_int(id: int, n: int) -> void { + if id < 0 { return } + if id >= ui_n { return } + let base = id * 96 + let at = 0 + let v = n + if v < 0 { + poke8(ui_dyn, base, 45) + at = 1 + v = 0 - v + } + if v == 0 { + poke8(ui_dyn, base + at, 48) + at = at + 1 + } else { + let digits = 0 + let t = v + while t > 0 { + digits = digits + 1 + t = t / 10 + } + let p = digits + while p > 0 { + let div = 1 + for k in 1 .. p { div = div * 10 } + poke8(ui_dyn, base + at, 48 + (v / div) % 10) + at = at + 1 + p = p - 1 + } + } + poke8(ui_dyn, base + at, 0) + poke32(ui_hasdyn, id, 1) +} + +fn rt_ui_focus(id: int) -> void { + if id < 0 { return } + if id >= ui_n { return } + ui_focus = id +} + +fn rt_ui_focused() -> int { + return ui_focus +} + +fn rt_ui_visible(id: int, v: int) -> void { + if id < 0 { return } + if id >= ui_n { return } + poke32(ui_visible, id, v) +} diff --git a/runtime/web/imports.txt b/runtime/web/imports.txt new file mode 100644 index 00000000..9f62a281 --- /dev/null +++ b/runtime/web/imports.txt @@ -0,0 +1,32 @@ +# runtime/web/imports.txt — every symbol a web build may leave undefined. +# +# ludicc passes this to wasm-ld as --allow-undefined-file, so these become the +# module's wasm imports and *anything else* undefined is a link error at build +# time rather than a LinkError in the browser. That matters because LLVM invents +# libcalls (calloc, bcmp, memmove) that ludicc never emitted: without this list +# they would silently become imports nobody implements. +# +# runtime/web/platform.js supplies all of them. + +# the window — the same five-function protocol runtime/native/cocoa.ll implements +win_open +win_poll +win_present +win_running +win_close + +# files: a preloaded image of the game's assets, plus localStorage for saves +web_fopen +web_fread +web_fwrite +web_fclose +web_fseek +web_ftell + +# stdin, stdout, the clock, and giving up +web_getchar +web_putchar +web_print_str +web_print_int +web_time +web_exit diff --git a/runtime/web/index.html b/runtime/web/index.html new file mode 100644 index 00000000..68007292 --- /dev/null +++ b/runtime/web/index.html @@ -0,0 +1,106 @@ + + + + + + +{{TITLE}} + + + + +

{{TITLE}}

+ +

loading…

+ +
+ + + + + + + + + +
+ + + + diff --git a/runtime/web/platform.js b/runtime/web/platform.js new file mode 100644 index 00000000..d531d89f --- /dev/null +++ b/runtime/web/platform.js @@ -0,0 +1,357 @@ +// ============================================================================ +// runtime/web/platform.js — the web's window, keyboard and filesystem. +// +// This file is the browser's answer to runtime/native/cocoa.ll, and it has the +// same job and the same size: implement the five-function platform protocol +// +// win_open(w, h, scale, title) win_poll() -> key win_present(fb, w, h) +// win_running() -> bool win_close() +// +// plus the handful of host services wasm has no OS to ask for — files, the +// clock, stdout. Nothing else. The game, the ECS, the framebuffer, the PNG +// decoder, the TrueType rasteriser and the UI are all compiled Ludic running +// inside the wasm module; no game logic passes through this file, and none of +// it is interpreted. +// +// const game = await LudicWeb.start({ wasm: 'chronorift.wasm', +// canvas: document.querySelector('canvas'), +// manifest: 'assets.json' }) +// ============================================================================ + +export const LudicWeb = { start }; + +// --------------------------------------------------------------------------- +// Keyboard. win_poll() reports the last key pressed since the previous frame, +// as a character code, or 0 for none — exactly what cocoa.ll reports. Arrow +// keys fold onto WASD and Escape onto 'q', so a game written for the native +// build needs no web-specific input handling. +// --------------------------------------------------------------------------- +const KEY_ALIASES = { + ArrowUp: 'w', ArrowLeft: 'a', ArrowDown: 's', ArrowRight: 'd', + Escape: 'q', Enter: '\r', Backspace: '\b', Tab: '\t', +}; + +function keyCode(ev) { + const alias = KEY_ALIASES[ev.key]; + if (alias) return alias.charCodeAt(0); + if (ev.key.length === 1) return ev.key.charCodeAt(0); + return 0; +} + +// --------------------------------------------------------------------------- +// A read-only image of the game's files, plus a writable overlay in +// localStorage for save games. +// +// The Ludic runtime opens assets with file_open()/file_read(), which on a +// native build is fopen/fread. The browser has no synchronous file access, so +// every file the game can open is fetched up front (see the manifest ludicc +// emits beside the .wasm) and served out of memory. Saves go the other way: +// file_open("game.sav","wb") buffers, and fclose commits to localStorage, so +// save/load survives a page reload. +// --------------------------------------------------------------------------- +export class Files { + constructor(preloaded, storageKey) { + this.assets = preloaded; // Map + this.storageKey = storageKey; + this.open = new Map(); // handle -> {data, pos, path, write} + this.next = 1; // 0 is NULL to the Ludic side + } + + saved(path) { + try { + const raw = localStorage.getItem(this.storageKey + path); + if (raw === null) return null; + const bytes = new Uint8Array(raw.length); + for (let i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i) & 0xff; + return bytes; + } catch { return null; } + } + + commit(path, data) { + try { + let raw = ''; + for (let i = 0; i < data.length; i += 0x8000) + raw += String.fromCharCode.apply(null, data.subarray(i, i + 0x8000)); + localStorage.setItem(this.storageKey + path, raw); + } catch (e) { + console.warn('ludic: could not persist', path, e); + } + } + + fopen(path, mode) { + const writing = mode.includes('w') || mode.includes('a'); + if (writing) { + const h = this.next++; + this.open.set(h, { path, pos: 0, write: true, chunks: [], size: 0 }); + return h; + } + // Reads prefer a save the player has made over the shipped asset. + const data = this.saved(path) || this.assets.get(path) || + this.assets.get(path.replace(/^\.\//, '')); + if (!data) return 0; // NULL: the game handles it + const h = this.next++; + this.open.set(h, { path, pos: 0, write: false, data }); + return h; + } + + fread(h, dst, want) { + const f = this.open.get(h); + if (!f || f.write) return 0; + const n = Math.max(0, Math.min(want, f.data.length - f.pos)); + dst.set(f.data.subarray(f.pos, f.pos + n)); + f.pos += n; + return n; + } + + fwrite(h, src, n) { + const f = this.open.get(h); + if (!f || !f.write) return 0; + f.chunks.push(src.slice(0, n)); // copy: wasm memory is reused + f.size += n; + f.pos += n; + return n; + } + + fclose(h) { + const f = this.open.get(h); + if (!f) return; + if (f.write) { + const all = new Uint8Array(f.size); + let at = 0; + for (const c of f.chunks) { all.set(c, at); at += c.length; } + this.commit(f.path, all); + } + this.open.delete(h); + } + + fseek(h, off, whence) { + const f = this.open.get(h); + if (!f) return -1; + const end = f.write ? f.size : f.data.length; + const base = whence === 1 ? f.pos : whence === 2 ? end : 0; + f.pos = Math.max(0, Math.min(end, base + off)); + return 0; + } + + ftell(h) { + const f = this.open.get(h); + return f ? f.pos : -1; + } +} + +// --------------------------------------------------------------------------- +// The canvas. win_present() hands over a pointer to the framebuffer — one +// 0x00RRGGBB word per pixel — which is transcoded into the RGBA byte order +// ImageData wants and blitted at the requested integer scale. +// --------------------------------------------------------------------------- +class Screen { + constructor(canvas) { + this.canvas = canvas; + this.ctx = null; + this.image = null; + this.w = 0; this.h = 0; + } + + open(w, h, scale, title) { + this.w = w; this.h = h; + this.canvas.width = w; + this.canvas.height = h; + // The backing store stays at the framebuffer's own resolution and CSS does + // the scaling, so a 320x240 game stays crisp on a HiDPI display. + // + // How big to draw it is the page's decision, not the platform layer's: a 3x + // 320x240 window is 720px tall and does not fit a laptop viewport once there + // is a title above it. So this publishes the framebuffer's dimensions and + // the scale the game asked for, and leaves the fitting to CSS — see the + // width rule in runtime/web/index.html. + const css = this.canvas.style; + css.setProperty('--ludic-w', String(w)); + css.setProperty('--ludic-h', String(h)); + css.setProperty('--ludic-scale', String(scale)); + css.aspectRatio = w + ' / ' + h; + css.height = 'auto'; + css.imageRendering = 'pixelated'; + this.ctx = this.canvas.getContext('2d', { alpha: false }); + this.ctx.imageSmoothingEnabled = false; + this.image = this.ctx.createImageData(w, h); + this.rgba = new Uint32Array(this.image.data.buffer); + if (title) document.title = title; + } + + present(words, w, h) { + if (!this.ctx) return; + if (w !== this.w || h !== this.h) this.open(w, h, 1, null); + const dst = this.rgba; + // Little-endian ImageData is 0xAABBGGRR; the framebuffer is 0x00RRGGBB. + for (let i = 0, n = w * h; i < n; i++) { + const c = words[i]; + dst[i] = 0xff000000 | ((c & 0xff) << 16) | (c & 0xff00) | ((c >>> 16) & 0xff); + } + this.ctx.putImageData(this.image, 0, 0); + } +} + +// --------------------------------------------------------------------------- +// Host — the memory views and the services wasm has no OS to ask for. +// +// A wasm module's linear memory is detached and replaced every time it grows, +// so every view has to be re-derived rather than cached across a call. Beyond +// that this is just the non-window half of the platform: files, stdin, stdout +// and the clock. The browser and Node need exactly the same set, so the Node +// test runner (tools/ludic-web/run.mjs) builds on this class too, and only the +// five win_* functions differ between the two hosts. +// --------------------------------------------------------------------------- +export class Host { + constructor({ files, stdin = '', log = console.log } = {}) { + this.files = files; + this.stdin = stdin; + this.stdinAt = 0; + this.log = log; + this.line = ''; + this.memory = null; + this.buffer = null; + this.running = 1; + this.exitCode = null; + } + + bind(memory) { this.memory = memory; this.sync(); } + + sync() { + if (this.memory.buffer !== this.buffer) { + this.buffer = this.memory.buffer; + this.u8 = new Uint8Array(this.buffer); + this.u32 = new Uint32Array(this.buffer); + } + } + + cstr(p) { + this.sync(); + let end = p; + while (this.u8[end] !== 0) end++; + return new TextDecoder().decode(this.u8.subarray(p, end)); + } + + flush() { if (this.line) { this.log(this.line); this.line = ''; } } + + imports() { + const fs = this.files; + return { + web_fopen: (path, mode) => fs.fopen(this.cstr(path), this.cstr(mode)), + web_fread: (h, dst, n) => { this.sync(); return fs.fread(h, this.u8.subarray(dst, dst + n), n); }, + web_fwrite: (h, src, n) => { this.sync(); return fs.fwrite(h, this.u8.subarray(src, src + n), n); }, + web_fclose: (h) => fs.fclose(h), + web_fseek: (h, off, whence) => fs.fseek(h, off, whence), + web_ftell: (h) => fs.ftell(h), + + web_getchar: () => (this.stdinAt < this.stdin.length ? this.stdin.charCodeAt(this.stdinAt++) : -1), + web_putchar: (c) => { if (c === 10) this.flush(); else this.line += String.fromCharCode(c); }, + web_print_str: (p) => { this.line += this.cstr(p); }, + // print_int(n) is printf("%d\n", n) natively, newline included. + web_print_int: (n) => { this.line += String(n); this.flush(); }, + web_time: () => Math.floor(Date.now() / 1000), + web_exit: (code) => { + this.running = 0; this.exitCode = code; this.flush(); + throw new ExitSignal(code); + }, + }; + } +} + +// --------------------------------------------------------------------------- +// start() — fetch the module and its assets, wire the imports, run the loop. +// +// The native entry point is `while (alive) frame();`. A browser tab cannot be +// held that way, so a web build exports the loop's parts instead — +// ludic_boot / ludic_frame / ludic_alive / ludic_teardown — and this drives +// them from requestAnimationFrame. The systems that run per frame, and their +// order, are identical; only who owns the loop changes. +// --------------------------------------------------------------------------- +async function start({ wasm, canvas, manifest = null, files = {}, onExit = null, + stdin = '', storageKey = 'ludic:' } = {}) { + const assets = new Map(); + for (const [path, bytes] of Object.entries(files)) assets.set(path, bytes); + + if (manifest) { + const list = await (await fetch(manifest)).json(); + await Promise.all(list.map(async (path) => { + const res = await fetch(path); + if (!res.ok) { console.warn('ludic: missing asset', path); return; } + assets.set(path, new Uint8Array(await res.arrayBuffer())); + })); + } + + const host = new Host({ files: new Files(assets, storageKey) }); + const screen = new Screen(canvas); + let pendingKey = 0; + + const env = { + ...host.imports(), + // The window, which is the only part of the platform the browser and the + // test runner do not share. + win_open: (w, h, scale, title) => screen.open(w, h, scale || 1, host.cstr(title)), + win_poll: () => { const k = pendingKey; pendingKey = 0; return k; }, + win_present: (fb, w, h) => { + host.sync(); + screen.present(host.u32.subarray(fb >>> 2, (fb >>> 2) + w * h), w, h); + }, + win_running: () => host.running, + win_close: () => { host.running = 0; }, + }; + + const { instance } = await WebAssembly.instantiateStreaming(fetch(wasm), { env }); + host.bind(instance.exports.memory); + + const { ludic_boot, ludic_frame, ludic_alive, ludic_teardown } = instance.exports; + + const onKey = (ev) => { + const k = keyCode(ev); + if (k) { pendingKey = k; ev.preventDefault(); } + }; + window.addEventListener('keydown', onKey); + + const game = { + instance, + exports: instance.exports, + // Lets a page wire on-screen buttons for touch devices: game.press('w'). + press: (k) => { pendingKey = typeof k === 'string' ? k.charCodeAt(0) : k; }, + stop: () => { host.running = 0; }, + }; + + let stopped = false; + const finish = () => { + if (stopped) return; + stopped = true; + window.removeEventListener('keydown', onKey); + try { ludic_teardown(); } catch (e) { if (!(e instanceof ExitSignal)) throw e; } + host.flush(); + if (onExit) onExit(host.exitCode ?? 0); + }; + + const step = () => { + if (stopped) return; + try { + if (!host.running || !ludic_alive()) return finish(); + ludic_frame(); + } catch (e) { + if (e instanceof ExitSignal) return finish(); + stopped = true; + window.removeEventListener('keydown', onKey); + throw e; + } + requestAnimationFrame(step); + }; + + try { ludic_boot(); } catch (e) { + if (!(e instanceof ExitSignal)) throw e; + finish(); + return game; + } + requestAnimationFrame(step); + return game; +} + +// os_exit() has to unwind the wasm frame it was called from; there is no +// process to terminate, so it throws and the loop treats it as the end. +export class ExitSignal extends Error { + constructor(code) { super('ludic: exit(' + code + ')'); this.code = code; } +} diff --git a/runtime/web/wasm.ll b/runtime/web/wasm.ll new file mode 100644 index 00000000..80a7c295 --- /dev/null +++ b/runtime/web/wasm.ll @@ -0,0 +1,369 @@ +; ============================================================================ +; runtime/web/wasm.ll — the web platform layer, written in LLVM IR. +; +; This is to the browser what runtime/native/cocoa.ll is to macOS: the one +; per-platform file, hand-written in the same IR ludicc emits, assembled by the +; same toolchain and handed to the same linker. No C is compiled here either. +; +; It exists because wasm32-unknown-unknown has no libc. The Ludic runtime +; (runtime/native/*.ludic) stands on a floor of ~15 platform calls — malloc, +; memcpy, fopen, getchar — and on a native target those are the OS's. On the +; web there is no OS underneath, so this file *is* the floor: +; +; * the allocator is implemented here, over wasm linear memory; +; * memcpy/memset/strlen are implemented here; +; * everything genuinely external — files, stdin, stdout, the clock, and the +; five win_* window functions — is a wasm import, resolved by +; runtime/web/platform.js. +; +; Nothing above this file changes for the web. core.ludic, image.ludic, +; truetype.ludic and ui.ludic compile to wasm unmodified. +; ============================================================================ + +target triple = "wasm32-unknown-unknown" + +declare i32 @llvm.wasm.memory.size.i32(i32) +declare i32 @llvm.wasm.memory.grow.i32(i32, i32) +declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1) +declare void @llvm.memmove.p0.p0.i32(ptr, ptr, i32, i1) +declare void @llvm.memset.p0.i32(ptr, i8, i32, i1) + +; wasm-ld places this symbol immediately after the static data segments; its +; *address* is where our heap may begin. +@__heap_base = external global i8 + +; --------------------------------------------------------------------------- +; The allocator. +; +; A first-fit free list over linear memory, growing the wasm memory with +; memory.grow when it runs out. Every block carries an 8-byte header +; [i32 payload_size][i32 next_free] and the pointer handed out is header+8, so +; free() is O(1) and malloc() reuses blocks of a size it has seen before — +; which is the shape of the load the PNG decoder actually makes (a dozen tiles +; of identical dimensions, each decode allocating and releasing the same three +; buffers). Blocks are split when the fit is loose; adjacent free blocks are +; not coalesced, which costs some fragmentation and buys a lot of simplicity. +; --------------------------------------------------------------------------- + +@ludic_brk = internal global i32 0 ; bump pointer; 0 until first use +@ludic_free = internal global i32 0 ; head of the free list, 0 = empty + +define ptr @malloc(i32 %n0) { +entry: + %small = icmp slt i32 %n0, 1 + %n1 = select i1 %small, i32 1, i32 %n0 + %pad = add i32 %n1, 7 + %n = and i32 %pad, -8 ; 8-byte aligned payloads + %head = load i32, ptr @ludic_free + br label %scan + +scan: ; walk the free list, first fit + %cur = phi i32 [ %head, %entry ], [ %nxt, %scan.next ] + %prev = phi i32 [ 0, %entry ], [ %cur, %scan.next ] + %end = icmp eq i32 %cur, 0 + br i1 %end, label %bump, label %check + +check: + %cp = inttoptr i32 %cur to ptr + %sz = load i32, ptr %cp + %nxtp = getelementptr i8, ptr %cp, i32 4 + %nxt = load i32, ptr %nxtp + %fits = icmp sge i32 %sz, %n + br i1 %fits, label %take, label %scan.next + +scan.next: + br label %scan + +take: ; unlink %cur from the free list + %first = icmp eq i32 %prev, 0 + br i1 %first, label %unlink.head, label %unlink.mid +unlink.head: + store i32 %nxt, ptr @ludic_free + br label %split +unlink.mid: + %pp = inttoptr i32 %prev to ptr + %pnp = getelementptr i8, ptr %pp, i32 4 + store i32 %nxt, ptr %pnp + br label %split + +split: ; give the tail back if it is worth it + %floor = add i32 %n, 40 + %loose = icmp sge i32 %sz, %floor + br i1 %loose, label %do.split, label %take.done +do.split: + store i32 %n, ptr %cp + %tail = sub i32 %sz, %n + %tailsz = sub i32 %tail, 8 + %tailat0 = add i32 %cur, 8 + %tailat = add i32 %tailat0, %n + %tp = inttoptr i32 %tailat to ptr + store i32 %tailsz, ptr %tp + %tnp = getelementptr i8, ptr %tp, i32 4 + %fh = load i32, ptr @ludic_free + store i32 %fh, ptr %tnp + store i32 %tailat, ptr @ludic_free + br label %take.done +take.done: + %reuse = getelementptr i8, ptr %cp, i32 8 + ret ptr %reuse + +bump: ; nothing reusable: take fresh memory + %b0 = load i32, ptr @ludic_brk + %new = icmp eq i32 %b0, 0 + br i1 %new, label %brk.init, label %brk.have +brk.init: + %hb = ptrtoint ptr @__heap_base to i32 + %hb7 = add i32 %hb, 7 + %hba = and i32 %hb7, -8 + br label %brk.have +brk.have: + %brk = phi i32 [ %b0, %bump ], [ %hba, %brk.init ] + %hdr = add i32 %brk, 8 + %need = add i32 %hdr, %n + %pages = call i32 @llvm.wasm.memory.size.i32(i32 0) + %have = shl i32 %pages, 16 + %short = icmp ugt i32 %need, %have + br i1 %short, label %grow, label %carve +grow: + %deficit = sub i32 %need, %have + %round = add i32 %deficit, 65535 + %want = lshr i32 %round, 16 + %got = call i32 @llvm.wasm.memory.grow.i32(i32 0, i32 %want) + %oom = icmp eq i32 %got, -1 + br i1 %oom, label %fail, label %carve +fail: + ret ptr null +carve: + %hp = inttoptr i32 %brk to ptr + store i32 %n, ptr %hp + store i32 %need, ptr @ludic_brk + %up = inttoptr i32 %hdr to ptr + ret ptr %up +} + +define void @free(ptr %p) { +entry: + %nil = icmp eq ptr %p, null + br i1 %nil, label %out, label %push +push: + %pi = ptrtoint ptr %p to i32 + %hi = sub i32 %pi, 8 + %hp = inttoptr i32 %hi to ptr + %np = getelementptr i8, ptr %hp, i32 4 + %fh = load i32, ptr @ludic_free + store i32 %fh, ptr %np + store i32 %hi, ptr @ludic_free + br label %out +out: + ret void +} + +; calloc and realloc are here because LLVM *invents* calls to them. It +; recognises the allocator by name, so an -O2 pass rewrites the +; mem_alloc()+mem_set(0) that core.ludic's rt_init does into a single calloc. +; The platform layer therefore has to be a complete enough libc for whatever the +; optimiser lowers to, not just for what ludicc emits. +define ptr @calloc(i32 %count, i32 %size) { +entry: + %n = mul i32 %count, %size + %p = call ptr @malloc(i32 %n) + %nil = icmp eq ptr %p, null + br i1 %nil, label %out, label %zero +zero: + call void @llvm.memset.p0.i32(ptr %p, i8 0, i32 %n, i1 false) + br label %out +out: + ret ptr %p +} + +; the block header carries its own size, so realloc can grow in place +define ptr @realloc(ptr %p, i32 %n) { +entry: + %nil = icmp eq ptr %p, null + br i1 %nil, label %fresh, label %known +fresh: + %f = call ptr @malloc(i32 %n) + ret ptr %f +known: + %pi = ptrtoint ptr %p to i32 + %hi = sub i32 %pi, 8 + %hp = inttoptr i32 %hi to ptr + %old = load i32, ptr %hp + %big = icmp sge i32 %old, %n + br i1 %big, label %keep, label %move +keep: + ret ptr %p +move: + %new = call ptr @malloc(i32 %n) + %bad = icmp eq ptr %new, null + br i1 %bad, label %fail, label %shift +fail: + ret ptr null +shift: + call void @llvm.memcpy.p0.p0.i32(ptr %new, ptr %p, i32 %old, i1 false) + call void @free(ptr %p) + ret ptr %new +} + +; --------------------------------------------------------------------------- +; Bulk memory and strings. +; +; size_t is 32-bit on wasm32, which is the signature ludicc emits for this +; target and the one LLVM canonicalises these names to. They use the wasm +; bulk-memory instructions (memory.copy / memory.fill) rather than a byte loop. +; --------------------------------------------------------------------------- + +define ptr @memcpy(ptr %d, ptr %s, i32 %n) { + call void @llvm.memcpy.p0.p0.i32(ptr %d, ptr %s, i32 %n, i1 false) + ret ptr %d +} + +define ptr @memset(ptr %d, i32 %c, i32 %n) { + %b = trunc i32 %c to i8 + call void @llvm.memset.p0.i32(ptr %d, i8 %b, i32 %n, i1 false) + ret ptr %d +} + +define ptr @memmove(ptr %d, ptr %s, i32 %n) { + call void @llvm.memmove.p0.p0.i32(ptr %d, ptr %s, i32 %n, i1 false) + ret ptr %d +} + +define i32 @memcmp(ptr %a, ptr %b, i32 %n) { +entry: + br label %loop +loop: + %i = phi i32 [ 0, %entry ], [ %i1, %step ] + %done = icmp uge i32 %i, %n + br i1 %done, label %same, label %test +test: + %ap = getelementptr i8, ptr %a, i32 %i + %bp = getelementptr i8, ptr %b, i32 %i + %av = load i8, ptr %ap + %bv = load i8, ptr %bp + %eq = icmp eq i8 %av, %bv + br i1 %eq, label %step, label %differ +step: + %i1 = add i32 %i, 1 + br label %loop +differ: + %az = zext i8 %av to i32 + %bz = zext i8 %bv to i32 + %r = sub i32 %az, %bz + ret i32 %r +same: + ret i32 0 +} + +; LLVM emits bcmp for comparisons whose result is only tested against zero. +define i32 @bcmp(ptr %a, ptr %b, i32 %n) { + %r = call i32 @memcmp(ptr %a, ptr %b, i32 %n) + ret i32 %r +} + +define i32 @strlen(ptr %s) { +entry: + br label %loop +loop: + %i = phi i32 [ 0, %entry ], [ %i1, %step ] + %cp = getelementptr i8, ptr %s, i32 %i + %c = load i8, ptr %cp + %z = icmp eq i8 %c, 0 + br i1 %z, label %out, label %step +step: + %i1 = add i32 %i, 1 + br label %loop +out: + ret i32 %i +} + +; --------------------------------------------------------------------------- +; Everything genuinely outside the module. +; +; These are wasm imports: platform.js supplies them, exactly as Cocoa supplies +; objc_msgSend to cocoa.ll. Files are served from a preloaded read-only image of +; the game's assets; the save file is backed by localStorage. +; --------------------------------------------------------------------------- + +declare i32 @web_fopen(ptr, ptr) ; -> handle, 0 on failure +declare i32 @web_fread(i32, ptr, i32) +declare i32 @web_fwrite(i32, ptr, i32) +declare void @web_fclose(i32) +declare i32 @web_fseek(i32, i32, i32) +declare i32 @web_ftell(i32) +declare i32 @web_time() +declare void @web_exit(i32) + +; A file handle is an opaque `ptr` to the Ludic runtime, and a small integer to +; JS. Handle 0 doubles as libc's NULL, so `file_open` failure checks work +; unchanged. +define ptr @fopen(ptr %path, ptr %mode) { + %h = call i32 @web_fopen(ptr %path, ptr %mode) + %p = inttoptr i32 %h to ptr + ret ptr %p +} + +define i32 @fread(ptr %buf, i32 %size, i32 %count, ptr %f) { + %bytes = mul i32 %size, %count + %h = ptrtoint ptr %f to i32 + %got = call i32 @web_fread(i32 %h, ptr %buf, i32 %bytes) + ret i32 %got +} + +define i32 @fwrite(ptr %buf, i32 %size, i32 %count, ptr %f) { + %bytes = mul i32 %size, %count + %h = ptrtoint ptr %f to i32 + %put = call i32 @web_fwrite(i32 %h, ptr %buf, i32 %bytes) + ret i32 %put +} + +define i32 @fclose(ptr %f) { + %h = ptrtoint ptr %f to i32 + call void @web_fclose(i32 %h) + ret i32 0 +} + +define i32 @fseek(ptr %f, i32 %off, i32 %whence) { + %h = ptrtoint ptr %f to i32 + %r = call i32 @web_fseek(i32 %h, i32 %off, i32 %whence) + ret i32 %r +} + +define i32 @ftell(ptr %f) { + %h = ptrtoint ptr %f to i32 + %r = call i32 @web_ftell(i32 %h) + ret i32 %r +} + +define i64 @time(ptr %slot) { + %s = call i32 @web_time() + %r = sext i32 %s to i64 + ret i64 %r +} + +define void @exit(i32 %code) noreturn { + call void @web_exit(i32 %code) + unreachable +} + +; stdin/stdout. A windowed web build never reads stdin — rt_poll() goes through +; win_poll() — but the intrinsic still has to resolve, and the headless path +; (used by the test suite under Node) genuinely uses both. +declare i32 @web_getchar() +declare void @web_putchar(i32) + +define i32 @getchar() { + %c = call i32 @web_getchar() + ret i32 %c +} + +define i32 @putchar(i32 %c) { + call void @web_putchar(i32 %c) + ret i32 %c +} + +; `print_str` is the one intrinsic ludicc lowers differently for the web: on a +; native target it goes through variadic printf("%s"), which wasm's strict +; signature checking makes awkward, so the web backend emits a direct call to +; @web_print_str instead. It is a pure import — platform.js defines it — and so +; needs no adapter here. diff --git a/selfhost/ast.ludic b/selfhost/ast.ludic new file mode 100644 index 00000000..dae73540 --- /dev/null +++ b/selfhost/ast.ludic @@ -0,0 +1,68 @@ +# ast.ludic — the node kinds and the single Node shape they share, plus the +# declaration tables the emitter reads. Mirrors compiler/front/ast.h + sem/. + +# declarations +const N_STRUCT: int = 0 +const N_FIELD: int = 1 +const N_VAR: int = 2 +const N_CONST: int = 3 +const N_FN: int = 4 +const N_PARAM: int = 5 +const N_MAIN: int = 6 +const N_BLOCK: int = 7 +const N_COMP: int = 8 +const N_SYS: int = 9 +const N_ARCH: int = 10 +const N_EXTERN: int = 11 +const N_UI: int = 12 +# statements +const S_LET: int = 10 +const S_ASSIGN: int = 11 +const S_IF: int = 12 +const S_WHILE: int = 13 +const S_FOR: int = 14 +const S_RETURN: int = 15 +const S_EXPR: int = 16 +const S_BREAK: int = 17 +const S_CONTINUE: int = 18 +const S_MATCH: int = 19 +const S_MARM: int = 20 +const S_QUERY: int = 21 +const S_SPAWN: int = 22 +const S_DESPAWN: int = 23 +const S_MACHINE: int = 24 +const S_STATE: int = 25 +const S_BECOME: int = 26 +# expressions +const E_INT: int = 30 +const E_STR: int = 31 +const E_BOOL: int = 32 +const E_ID: int = 33 +const E_CALL: int = 34 +const E_MEMBER: int = 35 +const E_INDEX: int = 36 +const E_BIN: int = 37 +const E_UN: int = 38 +const E_NEW: int = 39 +const E_FLOAT: int = 40 +const E_REC: int = 41 +const E_FINIT: int = 42 + +struct Node { + kind: int = 0 + s: ptr = ptr_null() # name / operator / string / type-of-new + ival: int = 0 # int literal, bool, flags + ty: ptr = ptr_null() # declared type (let/param/field/fn/var/const) + a: Node # fixed children (meaning per kind) + b: Node + c: Node + kids: []Node # variadic children + line: int = 0 +} + +fn node(kind: int) -> Node { + let n = new Node + n.kind = kind + n.kids = new []Node + return n +} diff --git a/selfhost/bootstrap-cfree.sh b/selfhost/bootstrap-cfree.sh new file mode 100755 index 00000000..45ed1077 --- /dev/null +++ b/selfhost/bootstrap-cfree.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# bootstrap-cfree.sh — rebuild the self-hosted compiler with NO C compiler. +# +# The C `ludicc` is retired to a one-time seed: selfhost/ludicc.seed.ll is the +# self-host compiler's own LLVM IR, a proven fixed point. From it plus clang +# (an IR assembler, the same floor Rust and Swift stand on) the compiler +# rebuilds itself and reproduces its own IR — the C source is never invoked. +# +# seed.ll --clang--> sh_seed +# sh_seed compiles selfhost.ludic -> out.ll +# assert out.ll == seed.ll (the seed is a true fixed point) +set -u +cd "$(dirname "$0")/.." +CC="${LUDIC_CC:-clang}" +B=build/cfree +mkdir -p "$B" + +# assemble the compiler straight from the checked-in seed — no C involved +$CC selfhost/ludicc.seed.ll -o "$B/sh_seed" 2>/dev/null || { echo "FAIL: assemble seed"; exit 1; } +echo " seed.ll --clang--> sh_seed (no C compiler used)" + +# regenerate the concatenated source the same way build.sh does (pure shell) +FRAGS="selfhost/str.ludic selfhost/buf.ludic selfhost/io.ludic selfhost/ast.ludic +selfhost/lex.ludic selfhost/parse.ludic selfhost/parse_game.ludic selfhost/emit_core.ludic selfhost/emit_head.ludic +selfhost/emit_addr.ludic selfhost/emit_intrin.ludic selfhost/emit_intrin2.ludic selfhost/emit_math.ludic selfhost/emit_new.ludic +selfhost/emit_expr.ludic selfhost/emit_stmt.ludic selfhost/emit_ecs.ludic selfhost/emit_query.ludic selfhost/emit_spawn.ludic selfhost/emit_game.ludic selfhost/emit_machine.ludic selfhost/emit_save.ludic selfhost/emit_ui.ludic selfhost/emit_decl.ludic selfhost/main.ludic" +{ echo "game SelfHost {"; for f in $FRAGS; do cat "$f"; echo; done; echo "}"; } > "$B/selfhost.ludic" + +# the seed-built compiler compiles its own source +"$B/sh_seed" "$B/selfhost.ludic" > "$B/out.ll" 2>/dev/null || { echo "FAIL: seed compiler self-compile"; exit 1; } +echo " sh_seed compiles selfhost.ludic -> out.ll ($(wc -l < "$B/out.ll" | tr -d ' ') lines)" + +if cmp -s "$B/out.ll" selfhost/ludicc.seed.ll; then + echo " ✅ out.ll == seed.ll — the compiler rebuilds itself with no C compiler" + exit 0 +else + echo " â�Œ out.ll != seed.ll (seed is stale — regenerate with ./selfhost/reseed.sh)" + diff "$B/out.ll" selfhost/ludicc.seed.ll | head + exit 1 +fi diff --git a/selfhost/bootstrap.sh b/selfhost/bootstrap.sh new file mode 100755 index 00000000..68658094 --- /dev/null +++ b/selfhost/bootstrap.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# bootstrap.sh — the self-hosting proof. +# +# stage0: the C compiler (build/ludicc) compiles the self-host source -> gen1 +# stage1: gen1 compiles the self-host source -> gen2 +# stage2: gen2 compiles the self-host source -> gen3 +# assert: gen2.ll == gen3.ll (the compiler reproduces itself exactly) +# +# gen1 is built by a *different* compiler (the C one), so its IR legitimately +# differs; gen2 == gen3 is the fixpoint that proves independence. +set -u +cd "$(dirname "$0")/.." +CC="${LUDIC_CC:-clang}" +B=build/boot +mkdir -p "$B" +say() { printf " %s\n" "$1"; } + +# stage 0: C compiler builds the self-host compiler (also writes build/selfhost.ludic) +./selfhost/build.sh build/ludicc "$B/gen1" >/dev/null 2>&1 || { echo "FAIL: stage0 build"; exit 1; } +say "stage0: C ludicc -> gen1 (self-host compiler)" + +# stage 1: gen1 compiles the self-host source to IR, assemble -> gen2 +"$B/gen1" build/selfhost.ludic > "$B/gen2.ll" 2>/dev/null || { echo "FAIL: gen1 self-compile"; exit 1; } +$CC "$B/gen2.ll" -o "$B/gen2" 2>/dev/null || { echo "FAIL: gen2 assemble"; exit 1; } +say "stage1: gen1 -> gen2.ll ($(wc -l < "$B/gen2.ll" | tr -d ' ') lines) -> gen2" + +# stage 2: gen2 compiles the self-host source to IR -> gen3 +"$B/gen2" build/selfhost.ludic > "$B/gen3.ll" 2>/dev/null || { echo "FAIL: gen2 self-compile"; exit 1; } +say "stage2: gen2 -> gen3.ll ($(wc -l < "$B/gen3.ll" | tr -d ' ') lines)" + +# the fixpoint +if cmp -s "$B/gen2.ll" "$B/gen3.ll"; then + rm -f build/selfhost.ludic + echo " ✅ FIXPOINT: gen2.ll == gen3.ll — the self-hosted compiler reproduces itself" + exit 0 +else + echo " â�Œ gen2.ll != gen3.ll" + diff "$B/gen2.ll" "$B/gen3.ll" | head + exit 1 +fi diff --git a/selfhost/buf.ludic b/selfhost/buf.ludic new file mode 100644 index 00000000..0d668a4e --- /dev/null +++ b/selfhost/buf.ludic @@ -0,0 +1,29 @@ +# buf.ludic — a growable byte buffer for building IR text. The emitter writes +# module-level material (types, globals, string constants) into one buffer and +# function bodies into another, then prints them in order. + +struct Buf { data: ptr = ptr_null(), len: int = 0, cap: int = 0 } + +fn buf_new() -> Buf { + let b = new Buf + b.cap = 256 + b.data = mem_alloc(b.cap) + b.len = 0 + return b +} +fn buf_ensure(b: Buf, extra: int) -> void { + if b.len + extra + 1 <= b.cap { return } + while b.len + extra + 1 > b.cap { b.cap = b.cap * 2 } + b.data = mem_realloc(b.data, b.cap) +} +fn buf_putc(b: Buf, c: int) -> void { + buf_ensure(b, 1) + poke8(b.data, b.len, c) + b.len = b.len + 1 +} +fn buf_puts(b: Buf, s: ptr) -> void { + let i = 0 + while peek8(s, i) != 0 { buf_putc(b, peek8(s, i)) i = i + 1 } +} +fn buf_puti(b: Buf, n: int) -> void { buf_puts(b, itoa(n)) } +fn buf_str(b: Buf) -> ptr { poke8(b.data, b.len, 0) return b.data } diff --git a/selfhost/build.sh b/selfhost/build.sh new file mode 100755 index 00000000..b2050eb5 --- /dev/null +++ b/selfhost/build.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# build.sh — assemble the self-host compiler from its fragments and compile it +# with the given ludicc (default: the C build/ludicc). +# ./selfhost/build.sh [ludicc] [outbin] +set -u +cd "$(dirname "$0")/.." +LC="${1:-build/ludicc}" +OUT="${2:-build/selfhost}" +mkdir -p build +FRAGS="selfhost/str.ludic +selfhost/buf.ludic +selfhost/io.ludic +selfhost/ast.ludic +selfhost/lex.ludic +selfhost/parse.ludic +selfhost/parse_game.ludic +selfhost/emit_core.ludic +selfhost/emit_head.ludic +selfhost/emit_addr.ludic +selfhost/emit_intrin.ludic +selfhost/emit_intrin2.ludic +selfhost/emit_math.ludic +selfhost/emit_new.ludic +selfhost/emit_expr.ludic +selfhost/emit_stmt.ludic +selfhost/emit_ecs.ludic +selfhost/emit_query.ludic +selfhost/emit_spawn.ludic +selfhost/emit_game.ludic +selfhost/emit_machine.ludic +selfhost/emit_save.ludic +selfhost/emit_ui.ludic +selfhost/emit_decl.ludic +selfhost/main.ludic" +SRC=build/selfhost.ludic +{ echo "game SelfHost {"; for f in $FRAGS; do cat "$f"; echo; done; echo "}"; } > "$SRC" +# the compiler emits IR to stdout; clang assembles and links it +"$LC" "$SRC" > "$OUT.ll" 2>/dev/null && ${LUDIC_CC:-clang} "$OUT.ll" -o "$OUT" 2>/dev/null +rc=$?; rm -f "$OUT.ll"; [ $rc -eq 0 ] diff --git a/selfhost/compile.sh b/selfhost/compile.sh new file mode 100755 index 00000000..cd7b0e90 --- /dev/null +++ b/selfhost/compile.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# compile.sh — compile a .ludic file with the self-hosted compiler and link it. +# ./selfhost/compile.sh +set -eu +cd "$(dirname "$0")/.." +SH="$1"; IN="$2"; OUT="$3" +"$SH" "$IN" > "$OUT.ll" +clang "$OUT.ll" -o "$OUT" diff --git a/selfhost/emit_addr.ludic b/selfhost/emit_addr.ludic new file mode 100644 index 00000000..d9d523bc --- /dev/null +++ b/selfhost/emit_addr.ludic @@ -0,0 +1,38 @@ +# emit_addr.ludic — addresses of lvalues (struct fields and slice elements), +# shared by expression loads and assignment stores. Each returns the address +# register; the element/field type is written into g_addr_ty. + +var g_addr_ty: ptr # out-param: the type at the computed address + +# address of `base.field` +fn emit_member_addr(e: Node) -> ptr { + let base = emit_expr(e.a) + let s = layout_node(base.ty) + if ptr_is_null(s) { perr(sconcat("member access on non-aggregate ", base.ty)) } + let fidx = field_index(s, e.s) + if fidx < 0 { perr(sconcat("no such field ", e.s)) } + g_addr_ty = field_type(s, e.s) + let r = nreg() + emit(" ") emit(r) emit(" = getelementptr inbounds ") emit(layout_ty(base.ty)) + emit(", ptr ") emit(base.code) emit(", i32 0, i32 ") emit(itoa(fidx)) emit("\n") + return r +} + +# address of `base[index]` (slices only in this subset) +fn emit_index_addr(e: Node) -> ptr { + let base = emit_expr(e.a) + if not is_slice_ty(base.ty) { perr("indexing a non-slice") } + let el = slice_elem(base.ty) + g_addr_ty = el + # load the data pointer from the slice header (field 0) + let dp = nreg() + emit(" ") emit(dp) emit(" = getelementptr inbounds %LSlice, ptr ") + emit(base.code) emit(", i32 0, i32 0\n") + let data = nreg() + emit(" ") emit(data) emit(" = load ptr, ptr ") emit(dp) emit("\n") + let ix = emit_expr(e.b) + let r = nreg() + emit(" ") emit(r) emit(" = getelementptr inbounds ") emit(llty(el)) + emit(", ptr ") emit(data) emit(", i32 ") emit(ix.code) emit("\n") + return r +} diff --git a/selfhost/emit_core.ludic b/selfhost/emit_core.ludic new file mode 100644 index 00000000..dbdcf2c1 --- /dev/null +++ b/selfhost/emit_core.ludic @@ -0,0 +1,139 @@ +# emit_core.ludic — emitter state, type mapping, struct/slice helpers, and the +# module header. Mirrors the pieces of compiler/back/ that this subset needs. +# structs and slices are references, so every non-scalar type lowers to `ptr`. + +struct Val { code: ptr = ptr_null(), ty: ptr = ptr_null() } +fn val(code: ptr, ty: ptr) -> Val { let v = new Val v.code = code v.ty = ty return v } + +var head: Buf # module-level: types, globals, string constants +var code: Buf # function bodies +var falloc: Buf # entry-block allocas for the current function +var ll_t: int = 0 # temp register counter (reset per function) +var ll_lbl: int = 0 # label counter +var ll_str: int = 0 # string-constant counter + +# local environment (parallel slices), reset per function +var loc_name: []ptr +var loc_reg: []ptr +var loc_ty: []ptr +var nloc: int = 0 + +# loop targets for break/continue (innermost last) +var brk_lbl: []ptr +var cnt_lbl: []ptr +var nloop: int = 0 + +var ret_ty: ptr # current function's return type +var g_term: bool = false # did the current block end in a terminator? +var self_stk: []ptr # entity-index slot (ip) per enclosing query, for self() +var nself: int = 0 +var mach_stk: []Node # enclosing `machine` nodes, so `become` finds its register +var nmach: int = 0 + +fn emit(s: ptr) -> void { buf_puts(code, s) } +fn emith(s: ptr) -> void { buf_puts(head, s) } + +# stack slots MUST live in the entry block (an alloca in a loop walks the stack +# off its end), so they go into a per-function buffer spliced in at entry. +fn emit_alloca(llt: ptr) -> ptr { + let r = sconcat("%t", itoa(ll_t)) ll_t = ll_t + 1 + buf_puts(falloc, " ") buf_puts(falloc, r) buf_puts(falloc, " = alloca ") buf_puts(falloc, llt) buf_puts(falloc, "\n") + return r +} + +# "%t" fresh register +fn sconcat(a: ptr, b: ptr) -> ptr { + let la = slen(a) let lb = slen(b) + let out = mem_alloc(la + lb + 1) + let i = 0 + while i < la { poke8(out, i, peek8(a, i)) i = i + 1 } + let j = 0 + while j < lb { poke8(out, la + j, peek8(b, j)) j = j + 1 } + poke8(out, la + lb, 0) + return out +} +fn nreg() -> ptr { let r = sconcat("%t", itoa(ll_t)) ll_t = ll_t + 1 return r } +fn lbl(pfx: ptr) -> ptr { let r = sconcat(pfx, itoa(ll_lbl)) ll_lbl = ll_lbl + 1 return r } + +# Ludic type -> LLVM type. int/bool are i32; everything else (ptr/str/struct/ +# slice) is a pointer; void is void. +fn llty(t: ptr) -> ptr { + if streq(t, "int") or streq(t, "bool") or streq(t, "fixed") { return "i32" } + if streq(t, "void") { return "void" } + return "ptr" +} + +fn is_slice_ty(t: ptr) -> bool { return peek8(t, 0) == 91 and peek8(t, 1) == 93 } # "[]" +fn slice_elem(t: ptr) -> ptr { return substr(t, 2, slen(t) - 2) } + +fn find_struct(name: ptr) -> Node { + let i = 0 + while i < len(prog) { + let d = prog[i] + if d.kind == N_STRUCT and streq(d.s, name) { return d } + i = i + 1 + } + return ptr_null() +} +fn is_struct_ty(t: ptr) -> bool { return not ptr_is_null(find_struct(t)) } + +fn find_arch(name: ptr) -> Node { + let i = 0 + while i < len(prog) { let d = prog[i] if d.kind == N_ARCH and streq(d.s, name) { return d } i = i + 1 } + return ptr_null() +} +fn find_comp(name: ptr) -> Node { + let i = 0 + while i < len(prog) { let d = prog[i] if d.kind == N_COMP and streq(d.s, name) { return d } i = i + 1 } + return ptr_null() +} +# a struct or a component — both have %Str_/%Cmp_ layouts with named fields +fn layout_node(name: ptr) -> Node { + let s = find_struct(name) if not ptr_is_null(s) { return s } + return find_comp(name) +} +fn layout_ty(name: ptr) -> ptr { + if not ptr_is_null(find_struct(name)) { return sconcat("%Str_", name) } + return sconcat("%Cmp_", name) +} + +fn field_index(s: Node, fname: ptr) -> int { + let i = 0 + while i < len(s.kids) { if streq(s.kids[i].s, fname) { return i } i = i + 1 } + return 0 - 1 +} +fn field_type(s: Node, fname: ptr) -> ptr { + let i = 0 + while i < len(s.kids) { if streq(s.kids[i].s, fname) { return s.kids[i].ty } i = i + 1 } + return "int" +} + +# find a global var/const by name +fn find_global(name: ptr) -> Node { + let i = 0 + while i < len(prog) { + let d = prog[i] + if d.kind == N_VAR and streq(d.s, name) { return d } + if d.kind == N_CONST and streq(d.s, name) { return d } + i = i + 1 + } + return ptr_null() +} +fn find_fn(name: ptr) -> Node { + let i = 0 + while i < len(prog) { let d = prog[i] if d.kind == N_FN and streq(d.s, name) { return d } i = i + 1 } + return ptr_null() +} + +# local variable environment +fn loc_reset() -> void { nloc = 0 } +fn loc_push(name: ptr, r: ptr, ty: ptr) -> void { + if nloc < len(loc_name) { loc_name[nloc] = name loc_reg[nloc] = r loc_ty[nloc] = ty } + else { push(loc_name, name) push(loc_reg, r) push(loc_ty, ty) } + nloc = nloc + 1 +} +fn loc_find(name: ptr) -> int { + let i = nloc - 1 + while i >= 0 { if streq(loc_name[i], name) { return i } i = i - 1 } + return 0 - 1 +} diff --git a/selfhost/emit_decl.ludic b/selfhost/emit_decl.ludic new file mode 100644 index 00000000..62175705 --- /dev/null +++ b/selfhost/emit_decl.ludic @@ -0,0 +1,104 @@ +# emit_decl.ludic — functions, main, and the whole-program driver. A function's +# body is built into a scratch buffer so entry-block allocas can be spliced in +# ahead of it (see emit_alloca). Returns go through a %retval slot + `ret` label. + +fn emit_params_sig(d: Node) -> void { + let i = 0 + while i < len(d.kids) { + if i > 0 { emit(", ") } + emit(llty(d.kids[i].ty)) emit(" %arg_") emit(d.kids[i].s) + i = i + 1 + } +} + +fn emit_fn(d: Node) -> void { + ll_t = 0 ll_lbl = 0 g_term = false loc_reset() nloop = 0 + ret_ty = d.ty + let fbody = buf_new() + falloc = buf_new() + let saved = code + code = fbody + let rl = llty(ret_ty) + if not streq(rl, "void") { buf_puts(falloc, " %retval = alloca ") buf_puts(falloc, rl) buf_puts(falloc, "\n") } + # params: store each incoming argument into a stack slot + let i = 0 + while i < len(d.kids) { + let p = d.kids[i] + let slot = emit_alloca(llty(p.ty)) + emit(" store ") emit(llty(p.ty)) emit(" %arg_") emit(p.s) emit(", ptr ") emit(slot) emit("\n") + loc_push(p.s, slot, p.ty) + i = i + 1 + } + emit_block(d.a) + if not g_term { emit(" br label %ret\n") } + emit("ret:\n") + if streq(rl, "void") { emit(" ret void\n") } + else { let r = emit_bind(sconcat("load ", sconcat(rl, ", ptr %retval"))) emit(" ret ") emit(rl) emit(" ") emit(r) emit("\n") } + code = saved + emit("define ") emit(rl) emit(" @fn_") emit(d.s) emit("(") emit_params_sig(d) emit(") {\nentry:\n") + emit(buf_str(falloc)) + emit(buf_str(fbody)) + emit("}\n\n") +} + +fn emit_main(d: Node) -> void { + ll_t = 0 ll_lbl = 0 g_term = false loc_reset() nloop = 0 + ret_ty = "int" + let fbody = buf_new() + falloc = buf_new() + let saved = code + code = fbody + buf_puts(falloc, " %retval = alloca i32\n") + emit(" store i32 %argc, ptr @L_argc\n") + emit(" store ptr %argv, ptr @L_argv\n") + emit(" store i32 0, ptr %retval\n") + emit_block(d.a) + if not g_term { emit(" br label %ret\n") } + emit("ret:\n") + let r = emit_bind("load i32, ptr %retval") + emit(" ret i32 ") emit(r) emit("\n") + code = saved + emit("define i32 @main(i32 %argc, ptr %argv) {\nentry:\n") + emit(buf_str(falloc)) + emit(buf_str(fbody)) + emit("}\n") +} + +fn emit_program() -> void { + head = buf_new() + code = buf_new() + loc_name = new []ptr loc_reg = new []ptr loc_ty = new []ptr + brk_lbl = new []ptr cnt_lbl = new []ptr + self_stk = new []ptr + mach_stk = new []Node + emit_header() + if has_ecs() { emit_ecs_storage() } + let i = 0 + while i < len(prog) { if prog[i].kind == N_FN { emit_fn(prog[i]) } i = i + 1 } + if has_ecs() { emit_ecs_allocator() emit_snapshot() } + if has_ui() { emit_ui_build() } + if has_systems() { emit_game_main() } + else { + i = 0 + while i < len(prog) { if prog[i].kind == N_MAIN { emit_main(prog[i]) } i = i + 1 } + } +} + +# Flush the emitted IR. With a null path it goes to stdout (the pipe the shell +# drivers read); with a path it is written to that file so ludicc can hand it to +# clang itself. +fn ir_flush(path: ptr) -> bool { + let h = buf_str(head) + let c = buf_str(code) + if ptr_is_null(path) { + print_str(h) + print_str(c) + return true + } + let f = file_open(path, "wb") + if ptr_is_null(f) { return false } + file_write(f, h, slen(h)) + file_write(f, c, slen(c)) + file_close(f) + return true +} diff --git a/selfhost/emit_ecs.ludic b/selfhost/emit_ecs.ludic new file mode 100644 index 00000000..720ab12d --- /dev/null +++ b/selfhost/emit_ecs.ludic @@ -0,0 +1,92 @@ +# emit_ecs.ludic — ECS storage and the entity allocator. For each component: +# a %Cmp_ layout, a dense @S_ store, and an @H_ "has this component" array. +# Entities are integer handles; L_alloc reuses freed slots. Mirrors the ECS +# parts of compiler/back/ir_decl.c. + +const MAX_ENT: int = 1024 + +fn has_ecs() -> bool { + let i = 0 + while i < len(prog) { let k = prog[i].kind if k == N_COMP or k == N_SYS { return true } i = i + 1 } + return false +} +fn has_systems() -> bool { + let i = 0 + while i < len(prog) { if prog[i].kind == N_SYS { return true } i = i + 1 } + return false +} + +fn emit_ecs_storage() -> void { + emith("@L_running = internal global i32 1\n") + emith("@L_key = internal global i32 0\n") + emith("@L_entc = internal global i32 0\n") + let me = itoa(MAX_ENT) + emith(sconcat("@L_alive = internal global [", sconcat(me, " x i32] zeroinitializer\n"))) + emith(sconcat("@L_kind = internal global [", sconcat(me, " x i32] zeroinitializer\n"))) + emith(sconcat("@L_freelist = internal global [", sconcat(me, " x i32] zeroinitializer\n"))) + emith("@L_freen = internal global i32 0\n") + let i = 0 + while i < len(prog) { + let c = prog[i] + if c.kind == N_COMP { + emith(sconcat("%Cmp_", sconcat(c.s, " = type { "))) + if len(c.kids) == 0 { emith("i32") } + let f = 0 + while f < len(c.kids) { if f > 0 { emith(", ") } emith(llty(c.kids[f].ty)) f = f + 1 } + emith(" }\n") + emith(sconcat("@S_", sconcat(c.s, sconcat(" = internal global [", sconcat(me, sconcat(" x %Cmp_", sconcat(c.s, "] zeroinitializer\n"))))))) + emith(sconcat("@H_", sconcat(c.s, sconcat(" = internal global [", sconcat(me, " x i8] zeroinitializer\n"))))) + } + i = i + 1 + } +} + +# L_reset(e): clear every has-flag and the archetype kind for entity e +fn emit_ecs_allocator() -> void { + let me = itoa(MAX_ENT) + emit("define void @L_reset(i32 %e) {\nentry:\n") + let i = 0 + while i < len(prog) { + if prog[i].kind == N_COMP { + let hn = sconcat("%h", itoa(i)) + emit(" ") emit(hn) emit(" = getelementptr inbounds [") emit(me) emit(" x i8], ptr @H_") emit(prog[i].s) emit(", i32 0, i32 %e\n") + emit(" store i8 0, ptr ") emit(hn) emit("\n") + } + i = i + 1 + } + emit(" %k = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_kind, i32 0, i32 %e\n") + emit(" store i32 0, ptr %k\n ret void\n}\n\n") + + emit("define i32 @L_alloc() {\nentry:\n") + emit(" %fn = load i32, ptr @L_freen\n") + emit(" %has = icmp sgt i32 %fn, 0\n") + emit(" br i1 %has, label %reuse, label %fresh\n") + emit("reuse:\n") + emit(" %fn1 = sub i32 %fn, 1\n") + emit(" store i32 %fn1, ptr @L_freen\n") + emit(" %fp = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_freelist, i32 0, i32 %fn1\n") + emit(" %re = load i32, ptr %fp\n") + emit(" br label %done\n") + emit("fresh:\n") + emit(" %ec = load i32, ptr @L_entc\n") + emit(" %ec1 = add i32 %ec, 1\n") + emit(" store i32 %ec1, ptr @L_entc\n") + emit(" br label %done\n") + emit("done:\n") + emit(" %e = phi i32 [ %re, %reuse ], [ %ec, %fresh ]\n") + emit(" call void @L_reset(i32 %e)\n") + emit(" %ap = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_alive, i32 0, i32 %e\n") + emit(" store i32 1, ptr %ap\n") + emit(" ret i32 %e\n}\n\n") + + emit("define void @L_free_entity(i32 %e) {\nentry:\n") + emit(" %ap = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_alive, i32 0, i32 %e\n") + emit(" store i32 0, ptr %ap\n") + emit(" call void @L_reset(i32 %e)\n") + emit(" %fn = load i32, ptr @L_freen\n") + emit(" %fp = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_freelist, i32 0, i32 %fn\n") + emit(" store i32 %e, ptr %fp\n") + emit(" %fn1 = add i32 %fn, 1\n") + emit(" store i32 %fn1, ptr @L_freen\n") + emit(" ret void\n}\n\n") +} diff --git a/selfhost/emit_expr.ludic b/selfhost/emit_expr.ludic new file mode 100644 index 00000000..331abc86 --- /dev/null +++ b/selfhost/emit_expr.ludic @@ -0,0 +1,168 @@ +# emit_expr.ludic — lower an expression to IR, returning its register and type. + +fn emit_load_at(addr: ptr, ty: ptr) -> Val { + let r = emit_bind(sconcat("load ", sconcat(llty(ty), sconcat(", ptr ", addr)))) + return val(r, ty) +} + +# short-circuit `and`/`or`: seed a slot with (left!=0), branch to decide whether +# to overwrite with (right!=0). +fn emit_logic(e: Node) -> Val { + let slot = emit_alloca("i32") + let la = emit_expr(e.a) + let lc = emit_bind(sconcat("icmp ne i32 ", sconcat(la.code, ", 0"))) + let lz = emit_bind(sconcat("zext i1 ", sconcat(lc, " to i32"))) + emit(" store i32 ") emit(lz) emit(", ptr ") emit(slot) emit("\n") + let ev = lbl("sc") let done = lbl("scend") + if streq(e.s, "and") { emit(" br i1 ") emit(lc) emit(", label %") emit(ev) emit(", label %") emit(done) emit("\n") } + else { emit(" br i1 ") emit(lc) emit(", label %") emit(done) emit(", label %") emit(ev) emit("\n") } + emit(ev) emit(":\n") + let rb = emit_expr(e.b) + let rc = emit_bind(sconcat("icmp ne i32 ", sconcat(rb.code, ", 0"))) + let rz = emit_bind(sconcat("zext i1 ", sconcat(rc, " to i32"))) + emit(" store i32 ") emit(rz) emit(", ptr ") emit(slot) emit("\n") + emit(" br label %") emit(done) emit("\n") + emit(done) emit(":\n") + return val(emit_bind(sconcat("load i32, ptr ", slot)), "bool") +} + +fn cmp_code(op: ptr) -> ptr { + if streq(op, "<") { return "slt" } + if streq(op, "<=") { return "sle" } + if streq(op, ">") { return "sgt" } + if streq(op, ">=") { return "sge" } + if streq(op, "==") { return "eq" } + return "ne" +} +fn is_cmp(op: ptr) -> bool { + return streq(op,"<") or streq(op,"<=") or streq(op,">") or streq(op,">=") or streq(op,"==") or streq(op,"!=") +} +fn arith_code(op: ptr) -> ptr { + if streq(op, "+") { return "add" } + if streq(op, "-") { return "sub" } + if streq(op, "*") { return "mul" } + if streq(op, "/") { return "sdiv" } + return "srem" +} + +# widen an int value to Q16.16 by shifting left 16 (a fixed value passes through) +fn to_fixed(v: Val) -> ptr { + if streq(v.ty, "fixed") { return v.code } + return emit_bind(sconcat("shl i32 ", sconcat(v.code, ", 16"))) +} + +fn emit_bin(e: Node) -> Val { + if streq(e.s, "and") or streq(e.s, "or") { return emit_logic(e) } + let a = emit_expr(e.a) + let b = emit_expr(e.b) + let fx = streq(a.ty, "fixed") or streq(b.ty, "fixed") + if is_cmp(e.s) { + let ac = a.code let bc = b.code + if fx { ac = to_fixed(a) bc = to_fixed(b) } + let c = emit_bind(sconcat("icmp ", sconcat(cmp_code(e.s), sconcat(" i32 ", sconcat(ac, sconcat(", ", bc)))))) + return val(emit_bind(sconcat("zext i1 ", sconcat(c, " to i32"))), "bool") + } + if fx { + let af = to_fixed(a) let bf = to_fixed(b) + if streq(e.s, "*") { + let a64 = emit_bind(sconcat("sext i32 ", sconcat(af, " to i64"))) + let b64 = emit_bind(sconcat("sext i32 ", sconcat(bf, " to i64"))) + let m = emit_bind(sconcat("mul i64 ", sconcat(a64, sconcat(", ", b64)))) + let sh = emit_bind(sconcat("ashr i64 ", sconcat(m, ", 16"))) + return val(emit_bind(sconcat("trunc i64 ", sconcat(sh, " to i32"))), "fixed") + } + if streq(e.s, "/") { + let a64 = emit_bind(sconcat("sext i32 ", sconcat(af, " to i64"))) + let ash = emit_bind(sconcat("shl i64 ", sconcat(a64, ", 16"))) + let b64 = emit_bind(sconcat("sext i32 ", sconcat(bf, " to i64"))) + let dv = emit_bind(sconcat("sdiv i64 ", sconcat(ash, sconcat(", ", b64)))) + return val(emit_bind(sconcat("trunc i64 ", sconcat(dv, " to i32"))), "fixed") + } + let r = emit_bind(sconcat(arith_code(e.s), sconcat(" i32 ", sconcat(af, sconcat(", ", bf))))) + return val(r, "fixed") + } + let r = emit_bind(sconcat(arith_code(e.s), sconcat(" i32 ", sconcat(a.code, sconcat(", ", b.code))))) + return val(r, "int") +} + +fn emit_call(e: Node) -> Val { + let name = e.a.s + if streq(name, "self") { if nself == 0 { return val("0", "entity") } return val(emit_bind(sconcat("load i32, ptr ", self_stk[nself - 1])), "entity") } + if streq(name, "key") { return val(emit_bind("load i32, ptr @L_key"), "int") } + if streq(name, "save") { emit(" call void @L_save()\n") return val("0", "void") } + if streq(name, "ui_build") { emit(" call void @ui_build()\n") return val("0", "void") } + if streq(name, "load") { return val(emit_bind("call i32 @L_load()"), "bool") } + if streq(name, "quit") { emit(" store i32 0, ptr @L_running\n") return val("0", "void") } + if streq(name, "len") { return emit_len(e) } + if streq(name, "push") { return emit_push(e) } + if streq(name, "fx") { let a = emit_expr(e.kids[0]) return val(emit_bind(sconcat("shl i32 ", sconcat(a.code, ", 16"))), "fixed") } + if streq(name, "flr") { let a = emit_expr(e.kids[0]) return val(emit_bind(sconcat("ashr i32 ", sconcat(a.code, ", 16"))), "int") } + if is_intrinsic(name) { return emit_intrinsic(name, e) } + if is_intrinsic2(name) { return emit_intrinsic2(name, e) } + if is_math_builtin(name) { return emit_math_builtin(name, e) } + let fn2 = find_fn(name) + let cname = name + if ptr_is_null(fn2) { + # a builtin like clear()/reg() is satisfied by its rt_ function + let rtname = sconcat("rt_", name) + fn2 = find_fn(rtname) + if ptr_is_null(fn2) { perr(sconcat("unknown function ", name)) } + cname = rtname + } + # evaluate args first (their IR is emitted before the call instruction) + let args = new []ptr + let atys = new []ptr + let i = 0 + while i < len(e.kids) { let v = emit_expr(e.kids[i]) push(args, v.code) push(atys, v.ty) i = i + 1 } + let rl = llty(fn2.ty) + emit(" ") + let rreg = "0" + if not streq(rl, "void") { rreg = nreg() emit(rreg) emit(" = ") } + emit("call ") emit(rl) emit(" @fn_") emit(cname) emit("(") + i = 0 + while i < len(args) { + if i > 0 { emit(", ") } + emit(llty(atys[i])) emit(" ") emit(args[i]) + i = i + 1 + } + emit(") +") + return val(rreg, fn2.ty) +} + +fn emit_expr(e: Node) -> Val { + if ptr_is_null(e) { return val("0", "int") } + if e.kind == E_INT { return val(itoa(e.ival), "int") } + if e.kind == E_FLOAT { return val(itoa(e.ival), "fixed") } + if e.kind == E_BOOL { return val(itoa(e.ival), "bool") } + if e.kind == E_STR { return val(emit_str_const(e.s), "str") } + if e.kind == E_NEW { + if is_slice_ty(e.s) { return emit_new_slice(e.s) } + return emit_new_struct(e.s) + } + if e.kind == E_ID { + let li = loc_find(e.s) + if li >= 0 { return emit_load_at(loc_reg[li], loc_ty[li]) } + let g = find_global(e.s) + if not ptr_is_null(g) { + if g.kind == N_CONST { return val(itoa(g.a.ival), "int") } + let r = emit_bind(sconcat("load ", sconcat(llty(g.ty), sconcat(", ptr @g_", e.s)))) + return val(r, g.ty) + } + # a UI_ that is not a const/var resolves to its widget index + if is_ui_ident(e.s) { return val(itoa(ui_index_of(e.s)), "int") } + perr(sconcat("unknown identifier ", e.s)) + } + if e.kind == E_MEMBER { let a = emit_member_addr(e) return emit_load_at(a, g_addr_ty) } + if e.kind == E_INDEX { let a = emit_index_addr(e) return emit_load_at(a, g_addr_ty) } + if e.kind == E_CALL { return emit_call(e) } + if e.kind == E_BIN { return emit_bin(e) } + if e.kind == E_UN { + let a = emit_expr(e.a) + if streq(e.s, "-") { return val(emit_bind(sconcat("sub i32 0, ", a.code)), "int") } + let c = emit_bind(sconcat("icmp eq i32 ", sconcat(a.code, ", 0"))) + return val(emit_bind(sconcat("zext i1 ", sconcat(c, " to i32"))), "bool") + } + perr("cannot emit expression") + return val("0", "int") +} diff --git a/selfhost/emit_game.ludic b/selfhost/emit_game.ludic new file mode 100644 index 00000000..15fed507 --- /dev/null +++ b/selfhost/emit_game.ludic @@ -0,0 +1,68 @@ +# emit_game.ludic — system functions and the frame loop. A system compiles to a +# void function; main() boots (Start systems), then runs the per-frame phases in +# order until the game stops. Runtime hooks (rt_init/poll/running/shutdown) are +# called only when the runtime defines them. + +fn emit_system_fn(sys: Node) -> void { + ll_t = 0 ll_lbl = 0 g_term = false loc_reset() nloop = 0 nself = 0 + ret_ty = "void" + let fbody = buf_new() + falloc = buf_new() + let saved = code + code = fbody + emit_block(sys.a) + if not g_term { emit(" br label %ret\n") } + emit("ret:\n ret void\n") + code = saved + emit("define void @sys_") emit(sys.s) emit("() {\nentry:\n") + emit(buf_str(falloc)) + emit(buf_str(fbody)) + emit("}\n\n") +} + +fn emit_calls_for_phase(phase: ptr) -> void { + let i = 0 + while i < len(prog) { + let d = prog[i] + if d.kind == N_SYS and streq(d.ty, phase) { emit(" call void @sys_") emit(d.s) emit("()\n") } + i = i + 1 + } +} + +fn emit_game_main() -> void { + # every system becomes a function first + let i = 0 + while i < len(prog) { if prog[i].kind == N_SYS { emit_system_fn(prog[i]) } i = i + 1 } + + emit("define i32 @main(i32 %argc, ptr %argv) {\nentry:\n") + emit(" store i32 %argc, ptr @L_argc\n") + emit(" store ptr %argv, ptr @L_argv\n") + if not ptr_is_null(find_fn("rt_init")) { emit(" call void @fn_rt_init()\n") } + emit_calls_for_phase("Start") + emit(" br label %loop\n") + emit("loop:\n") + let r = emit_bind("load i32, ptr @L_running") + let rc = emit_bind(sconcat("icmp ne i32 ", sconcat(r, ", 0"))) + if not ptr_is_null(find_fn("rt_running")) { + let pr = emit_bind("call i32 @fn_rt_running()") + let pc = emit_bind(sconcat("icmp ne i32 ", sconcat(pr, ", 0"))) + let go = emit_bind(sconcat("and i1 ", sconcat(rc, sconcat(", ", pc)))) + emit(" br i1 ") emit(go) emit(", label %body, label %done\n") + } else { + emit(" br i1 ") emit(rc) emit(", label %body, label %done\n") + } + emit("body:\n") + if not ptr_is_null(find_fn("rt_poll")) { + let k = emit_bind("call i32 @fn_rt_poll()") + emit(" store i32 ") emit(k) emit(", ptr @L_key\n") + } + emit_calls_for_phase("Input") + emit_calls_for_phase("FixedUpdate") + emit_calls_for_phase("Update") + emit_calls_for_phase("LateUpdate") + emit_calls_for_phase("Render") + emit(" br label %loop\n") + emit("done:\n") + if not ptr_is_null(find_fn("rt_shutdown")) { emit(" call void @fn_rt_shutdown()\n") } + emit(" ret i32 0\n}\n") +} diff --git a/selfhost/emit_head.ludic b/selfhost/emit_head.ludic new file mode 100644 index 00000000..0d33c28d --- /dev/null +++ b/selfhost/emit_head.ludic @@ -0,0 +1,108 @@ +# emit_head.ludic — string constants and the module header (libc declarations, +# the slice header type, struct layouts, globals, argv, format strings). + +fn hexdig(n: int) -> int { if n < 10 { return 48 + n } return 55 + n } # 0-9 A-F + +# emit `@.strN = ... c"escaped\00"` and return its name; % and non-print -> \XX +fn emit_str_const(s: ptr) -> ptr { + let name = sconcat("@.str", itoa(ll_str)) + ll_str = ll_str + 1 + let n = slen(s) + emith(name) emith(" = private unnamed_addr constant [") + emith(itoa(n + 1)) emith(" x i8] c\"") + let i = 0 + while i < n { + let c = peek8(s, i) + if c == 34 or c == 92 or c < 32 or c > 126 { + buf_putc(head, 92) # backslash + buf_putc(head, hexdig(c / 16)) + buf_putc(head, hexdig(c % 16)) + } else { buf_putc(head, c) } + i = i + 1 + } + emith("\\00\"\n") + return name +} + +# a fresh SSA register bound to a `getelementptr`, returned as its name +fn emit_gep_i8(base: ptr, idx: ptr) -> ptr { + let r = nreg() + emit(" ") emit(r) emit(" = getelementptr inbounds i8, ptr ") + emit(base) emit(", i32 ") emit(idx) emit("\n") + return r +} + +# the constant initializer for a global var: a literal, or 0/null +fn global_init(d: Node) -> ptr { + if ptr_is_null(d.a) { if streq(llty(d.ty), "ptr") { return "null" } return "0" } + let e = d.a + if e.kind == E_INT or e.kind == E_FLOAT or e.kind == E_BOOL { return itoa(e.ival) } + if e.kind == E_UN and streq(e.s, "-") and e.a.kind == E_INT { return sconcat("-", itoa(e.a.ival)) } + if streq(llty(d.ty), "ptr") { return "null" } + return "0" +} + +fn emit_header() -> void { + emith("; Ludic (self-hosted) -> LLVM IR\n") + emith("declare i32 @printf(ptr, ...)\n") + emith("declare ptr @malloc(i64)\n") + emith("declare ptr @realloc(ptr, i64)\n") + emith("declare void @free(ptr)\n") + emith("declare ptr @fopen(ptr, ptr)\n") + emith("declare i64 @fread(ptr, i64, i64, ptr)\n") + emith("declare i64 @fwrite(ptr, i64, i64, ptr)\n") + emith("declare i32 @fseek(ptr, i64, i32)\n") + emith("declare i64 @ftell(ptr)\n") + emith("declare i32 @fclose(ptr)\n") + emith("declare void @exit(i32)\n") + emith("declare i32 @system(ptr)\n") + emith("declare ptr @getenv(ptr)\n") + emith("declare ptr @memcpy(ptr, ptr, i64)\n") + emith("declare ptr @memset(ptr, i32, i64)\n") + emith("declare i64 @strlen(ptr)\n") + emith("declare i32 @getchar()\n") + emith("declare i32 @putchar(i32)\n") + emith("declare i64 @time(ptr)\n") + emith("declare void @win_open(i32, i32, i32, ptr)\n") + emith("declare i32 @win_poll()\n") + emith("declare void @win_present(ptr, i32, i32)\n") + emith("declare i32 @win_running()\n") + emith("declare void @win_close()\n") + emith("@__stderrp = external global ptr\n") + emith("@.fmt_str = private unnamed_addr constant [3 x i8] c\"%s\\00\"\n") + emith("@.fmt_int = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\"\n") + emith("@L_argc = internal global i32 0\n") + emith("@L_argv = internal global ptr null\n") + emith("@.gametitle = private unnamed_addr constant [") + emith(itoa(slen(g_game_name) + 1)) emith(" x i8] c\"") emith(g_game_name) emith("\\00\"\n") + emith("%LSlice = type { ptr, i32, i32 }\n") + # struct layouts + let i = 0 + while i < len(prog) { + let d = prog[i] + if d.kind == N_STRUCT { + emith("%Str_") emith(d.s) emith(" = type { ") + if len(d.kids) == 0 { emith("i32") } + let f = 0 + while f < len(d.kids) { + if f > 0 { emith(", ") } + emith(llty(d.kids[f].ty)) + f = f + 1 + } + emith(" }\n") + } + i = i + 1 + } + # globals (vars) — aggregates/pointers default to null, scalars to 0 + i = 0 + while i < len(prog) { + let d = prog[i] + if d.kind == N_VAR { + emith("@g_") emith(d.s) emith(" = internal global ") + emith(llty(d.ty)) emith(" ") + emith(global_init(d)) + emith("\n") + } + i = i + 1 + } +} diff --git a/selfhost/emit_intrin.ludic b/selfhost/emit_intrin.ludic new file mode 100644 index 00000000..13e530eb --- /dev/null +++ b/selfhost/emit_intrin.ludic @@ -0,0 +1,142 @@ +# emit_intrin.ludic — the low-level intrinsics the self-host source uses, each +# lowered to the same libc/inline IR the C backend emits. Returns a Val via +# g_intrin_val and sets g_intrin_ok when `name` was an intrinsic. + +var g_intrin_ok: bool = false + +# is `name` a low-level intrinsic? A pure name check, so it can gate dispatch +# without evaluating arguments (which could clobber shared state). +fn is_intrinsic(name: ptr) -> bool { + if streq(name,"ptr_null") or streq(name,"mem_alloc") or streq(name,"mem_realloc") { return true } + if streq(name,"peek8") or streq(name,"poke8") or streq(name,"ptr_is_null") { return true } + if streq(name,"file_open") or streq(name,"file_read") or streq(name,"file_write") { return true } + if streq(name,"file_seek") or streq(name,"file_tell") or streq(name,"file_close") { return true } + if streq(name,"print_str") or streq(name,"print_int") { return true } + if streq(name,"os_argc") or streq(name,"os_arg") or streq(name,"os_exit") or streq(name,"file_stderr") { return true } + if streq(name,"os_system") or streq(name,"os_getenv") { return true } + if streq(name,"shl") or streq(name,"shr") or streq(name,"band") or streq(name,"bor") or streq(name,"bxor") or streq(name,"bnot") { return true } + if streq(name,"peek32") or streq(name,"poke32") { return true } + return false +} +# emit " = \n" and return r +fn emit_bind(rest: ptr) -> ptr { let r = nreg() emit(" ") emit(r) emit(" = ") emit(rest) emit("\n") return r } + +fn arg_code(e: Node, i: int) -> ptr { let v = emit_expr(e.kids[i]) return v.code } + +fn emit_intrinsic(name: ptr, e: Node) -> Val { + g_intrin_ok = true + if streq(name, "ptr_null") { return val("null", "ptr") } + if streq(name, "mem_alloc") { + let n = arg_code(e, 0) + let w = emit_bind(sconcat("zext i32 ", sconcat(n, " to i64"))) + return val(emit_bind(sconcat("call ptr @malloc(i64 ", sconcat(w, ")"))), "ptr") + } + if streq(name, "mem_realloc") { + let p = arg_code(e, 0) let n = arg_code(e, 1) + let w = emit_bind(sconcat("zext i32 ", sconcat(n, " to i64"))) + return val(emit_bind(sconcat("call ptr @realloc(ptr ", sconcat(p, sconcat(", i64 ", sconcat(w, ")"))))), "ptr") + } + if streq(name, "peek8") { + let p = arg_code(e, 0) let i = arg_code(e, 1) + let a = emit_gep_i8(p, i) + let b = emit_bind(sconcat("load i8, ptr ", a)) + return val(emit_bind(sconcat("zext i8 ", sconcat(b, " to i32"))), "int") + } + if streq(name, "poke8") { + let p = arg_code(e, 0) let i = arg_code(e, 1) let v = arg_code(e, 2) + let a = emit_gep_i8(p, i) + let t = emit_bind(sconcat("trunc i32 ", sconcat(v, " to i8"))) + emit(" store i8 ") emit(t) emit(", ptr ") emit(a) emit("\n") + return val("0", "void") + } + if streq(name, "ptr_is_null") { + let p = arg_code(e, 0) + let c = emit_bind(sconcat("icmp eq ptr ", sconcat(p, ", null"))) + return val(emit_bind(sconcat("zext i1 ", sconcat(c, " to i32"))), "bool") + } + if streq(name, "file_open") { + let p = arg_code(e, 0) let m = arg_code(e, 1) + return val(emit_bind(sconcat("call ptr @fopen(ptr ", sconcat(p, sconcat(", ptr ", sconcat(m, ")"))))), "ptr") + } + if streq(name, "file_read") or streq(name, "file_write") { + let f = arg_code(e, 0) let b = arg_code(e, 1) let n = arg_code(e, 2) + let w = emit_bind(sconcat("zext i32 ", sconcat(n, " to i64"))) + let fn2 = "@fread" + if streq(name, "file_write") { fn2 = "@fwrite" } + let r = emit_bind(sconcat("call i64 ", sconcat(fn2, sconcat("(ptr ", sconcat(b, sconcat(", i64 1, i64 ", sconcat(w, sconcat(", ptr ", sconcat(f, ")"))))))))) + return val(emit_bind(sconcat("trunc i64 ", sconcat(r, " to i32"))), "int") + } + if streq(name, "file_seek") { + let f = arg_code(e, 0) let off = arg_code(e, 1) let wh = arg_code(e, 2) + let o = emit_bind(sconcat("sext i32 ", sconcat(off, " to i64"))) + return val(emit_bind(sconcat("call i32 @fseek(ptr ", sconcat(f, sconcat(", i64 ", sconcat(o, sconcat(", i32 ", sconcat(wh, ")"))))))), "int") + } + if streq(name, "file_tell") { + let f = arg_code(e, 0) + let r = emit_bind(sconcat("call i64 @ftell(ptr ", sconcat(f, ")"))) + return val(emit_bind(sconcat("trunc i64 ", sconcat(r, " to i32"))), "int") + } + if streq(name, "file_close") { + let f = arg_code(e, 0) + emit(" call i32 @fclose(ptr ") emit(f) emit(")\n") + return val("0", "void") + } + if streq(name, "print_str") { + let s = arg_code(e, 0) + emit(" call i32 (ptr, ...) @printf(ptr @.fmt_str, ptr ") emit(s) emit(")\n") + return val("0", "void") + } + if streq(name, "print_int") { + let n = arg_code(e, 0) + emit(" call i32 (ptr, ...) @printf(ptr @.fmt_int, i32 ") emit(n) emit(")\n") + return val("0", "void") + } + if streq(name, "os_argc") { return val(emit_bind("load i32, ptr @L_argc"), "int") } + if streq(name, "os_arg") { + let i = arg_code(e, 0) + let v = emit_bind("load ptr, ptr @L_argv") + let q = emit_bind(sconcat("getelementptr ptr, ptr ", sconcat(v, sconcat(", i32 ", i)))) + return val(emit_bind(sconcat("load ptr, ptr ", q)), "str") + } + if streq(name, "os_exit") { + let n = arg_code(e, 0) + emit(" call void @exit(i32 ") emit(n) emit(")\n") + emit(" unreachable\n") + g_term = true + return val("0", "void") + } + if streq(name, "file_stderr") { return val(emit_bind("load ptr, ptr @__stderrp"), "ptr") } + if streq(name, "os_system") { + let c = arg_code(e, 0) + return val(emit_bind(sconcat("call i32 @system(ptr ", sconcat(c, ")"))), "int") + } + if streq(name, "os_getenv") { + let n = arg_code(e, 0) + return val(emit_bind(sconcat("call ptr @getenv(ptr ", sconcat(n, ")"))), "str") + } + if streq(name, "bnot") { let a = arg_code(e, 0) return val(emit_bind(sconcat("xor i32 ", sconcat(a, ", -1"))), "int") } + if streq(name,"shl") or streq(name,"shr") or streq(name,"band") or streq(name,"bor") or streq(name,"bxor") { + let a = arg_code(e, 0) let b = arg_code(e, 1) + let opc = "shl" + if streq(name,"shr") { opc = "lshr" } + if streq(name,"band") { opc = "and" } + if streq(name,"bor") { opc = "or" } + if streq(name,"bxor") { opc = "xor" } + return val(emit_bind(sconcat(opc, sconcat(" i32 ", sconcat(a, sconcat(", ", b))))), "int") + } + if streq(name, "peek32") { + let p = arg_code(e, 0) let i = arg_code(e, 1) + let g = nreg() + emit(" ") emit(g) emit(" = getelementptr inbounds i32, ptr ") emit(p) emit(", i32 ") emit(i) emit("\n") + return val(emit_bind(sconcat("load i32, ptr ", g)), "int") + } + if streq(name, "poke32") { + let p = arg_code(e, 0) let i = arg_code(e, 1) let v = arg_code(e, 2) + let g = nreg() + emit(" ") emit(g) emit(" = getelementptr inbounds i32, ptr ") emit(p) emit(", i32 ") emit(i) emit("\n") + emit(" store i32 ") emit(v) emit(", ptr ") emit(g) emit("\n") + return val("0", "void") + } + g_intrin_ok = false + return val("0", "void") +} diff --git a/selfhost/emit_intrin2.ludic b/selfhost/emit_intrin2.ludic new file mode 100644 index 00000000..f1d6a636 --- /dev/null +++ b/selfhost/emit_intrin2.ludic @@ -0,0 +1,95 @@ +# emit_intrin2.ludic — the rest of the low-level intrinsics: raw memory, fixed +# memory access, pointer arithmetic, stdio, time, and the windowing hooks. +# Matches compiler/back/ir_intrin.c. Reached from emit_intrinsic's fall-through. + +var g_windowed: bool = false # headless by default (games read stdin / dump PPM) + +fn is_intrinsic2(name: ptr) -> bool { + if streq(name,"mem_free") or streq(name,"mem_copy") or streq(name,"mem_set") { return true } + if streq(name,"ptr_add") or streq(name,"read_byte") or streq(name,"write_byte") { return true } + if streq(name,"str_len") or streq(name,"os_time") { return true } + if streq(name,"peekf") or streq(name,"pokef") or streq(name,"as_fixed") or streq(name,"as_int") { return true } + if streq(name,"peekp") or streq(name,"pokep") { return true } + if streq(name,"is_windowed") or streq(name,"game_title") { return true } + if streq(name,"win_open") or streq(name,"win_poll") or streq(name,"win_present") { return true } + if streq(name,"win_running") or streq(name,"win_close") { return true } + return false +} + +fn emit_intrinsic2(name: ptr, e: Node) -> Val { + if streq(name, "mem_free") { + let p = arg_code(e, 0) emit(" call void @free(ptr ") emit(p) emit(")\n") return val("0", "void") + } + if streq(name, "mem_copy") { + let d = arg_code(e, 0) let s = arg_code(e, 1) let n = arg_code(e, 2) + let w = emit_bind(sconcat("zext i32 ", sconcat(n, " to i64"))) + emit(" call ptr @memcpy(ptr ") emit(d) emit(", ptr ") emit(s) emit(", i64 ") emit(w) emit(")\n") + return val("0", "void") + } + if streq(name, "mem_set") { + let p = arg_code(e, 0) let v = arg_code(e, 1) let n = arg_code(e, 2) + let w = emit_bind(sconcat("zext i32 ", sconcat(n, " to i64"))) + emit(" call ptr @memset(ptr ") emit(p) emit(", i32 ") emit(v) emit(", i64 ") emit(w) emit(")\n") + return val("0", "void") + } + if streq(name, "ptr_add") { + let p = arg_code(e, 0) let n = arg_code(e, 1) + let g = nreg() + emit(" ") emit(g) emit(" = getelementptr inbounds i8, ptr ") emit(p) emit(", i32 ") emit(n) emit("\n") + return val(g, "ptr") + } + if streq(name, "read_byte") { return val(emit_bind("call i32 @getchar()"), "int") } + if streq(name, "write_byte") { + let v = arg_code(e, 0) emit(" call i32 @putchar(i32 ") emit(v) emit(")\n") return val("0", "void") + } + if streq(name, "str_len") { + let s = arg_code(e, 0) + let r = emit_bind(sconcat("call i64 @strlen(ptr ", sconcat(s, ")"))) + return val(emit_bind(sconcat("trunc i64 ", sconcat(r, " to i32"))), "int") + } + if streq(name, "os_time") { + let r = emit_bind("call i64 @time(ptr null)") + return val(emit_bind(sconcat("trunc i64 ", sconcat(r, " to i32"))), "int") + } + if streq(name, "peekf") { + let p = arg_code(e, 0) let i = arg_code(e, 1) + let g = nreg() emit(" ") emit(g) emit(" = getelementptr inbounds i32, ptr ") emit(p) emit(", i32 ") emit(i) emit("\n") + return val(emit_bind(sconcat("load i32, ptr ", g)), "fixed") + } + if streq(name, "pokef") { + let p = arg_code(e, 0) let i = arg_code(e, 1) let v = arg_code(e, 2) + let g = nreg() emit(" ") emit(g) emit(" = getelementptr inbounds i32, ptr ") emit(p) emit(", i32 ") emit(i) emit("\n") + emit(" store i32 ") emit(v) emit(", ptr ") emit(g) emit("\n") + return val("0", "void") + } + if streq(name, "peekp") { + let p = arg_code(e, 0) let i = arg_code(e, 1) + let g = nreg() emit(" ") emit(g) emit(" = getelementptr inbounds ptr, ptr ") emit(p) emit(", i32 ") emit(i) emit("\n") + return val(emit_bind(sconcat("load ptr, ptr ", g)), "ptr") + } + if streq(name, "pokep") { + let p = arg_code(e, 0) let i = arg_code(e, 1) let v = arg_code(e, 2) + let g = nreg() emit(" ") emit(g) emit(" = getelementptr inbounds ptr, ptr ") emit(p) emit(", i32 ") emit(i) emit("\n") + emit(" store ptr ") emit(v) emit(", ptr ") emit(g) emit("\n") + return val("0", "void") + } + if streq(name, "as_fixed") { let a = emit_expr(e.kids[0]) return val(a.code, "fixed") } + if streq(name, "as_int") { let a = emit_expr(e.kids[0]) return val(a.code, "int") } + if streq(name, "is_windowed") { if g_windowed { return val("1", "bool") } return val("0", "bool") } + if streq(name, "game_title") { return val("@.gametitle", "str") } + # windowing hooks — declared external; only reached on the is_windowed() branch + if streq(name, "win_poll") { return val(emit_bind("call i32 @win_poll()"), "int") } + if streq(name, "win_running") { return val(emit_bind("call i32 @win_running()"), "bool") } + if streq(name, "win_open") { + let a = arg_code(e, 0) let b = arg_code(e, 1) let c = arg_code(e, 2) let d = arg_code(e, 3) + emit(" call void @win_open(i32 ") emit(a) emit(", i32 ") emit(b) emit(", i32 ") emit(c) emit(", ptr ") emit(d) emit(")\n") + return val("0", "void") + } + if streq(name, "win_present") { + let a = arg_code(e, 0) let b = arg_code(e, 1) let c = arg_code(e, 2) + emit(" call void @win_present(ptr ") emit(a) emit(", i32 ") emit(b) emit(", i32 ") emit(c) emit(")\n") + return val("0", "void") + } + if streq(name, "win_close") { emit(" call void @win_close()\n") return val("0", "void") } + return val("0", "void") +} diff --git a/selfhost/emit_machine.ludic b/selfhost/emit_machine.ludic new file mode 100644 index 00000000..85ab1e33 --- /dev/null +++ b/selfhost/emit_machine.ludic @@ -0,0 +1,39 @@ +# emit_machine.ludic — `machine { state Name = v { .. } }` dispatches on a +# register's value; `become Name` stores the target state's value back. Both are +# reg()/setreg() calls, resolved to the runtime like any other builtin. + +fn emit_machine(st: Node) -> void { + let regv = emit_expr(st.a) + let s = emit_bind(sconcat("call i32 @fn_rt_reg(i32 ", sconcat(regv.code, ")"))) + if nmach < len(mach_stk) { mach_stk[nmach] = st } else { push(mach_stk, st) } + nmach = nmach + 1 + let endl = lbl("smend") + let i = 0 + while i < len(st.kids) { + let state = st.kids[i] + let v = emit_expr(state.b) + let c = emit_bind(sconcat("icmp eq i32 ", sconcat(s, sconcat(", ", v.code)))) + let body = lbl("sbody") let nxt = lbl("sarm") + emit(" br i1 ") emit(c) emit(", label %") emit(body) emit(", label %") emit(nxt) emit("\n") + emit(body) emit(":\n") g_term = false + emit_block(state.a) + if not g_term { emit(" br label %") emit(endl) emit("\n") } + emit(nxt) emit(":\n") g_term = false + i = i + 1 + } + if not g_term { emit(" br label %") emit(endl) emit("\n") } + emit(endl) emit(":\n") g_term = false + nmach = nmach - 1 +} + +fn emit_become(st: Node) -> void { + if nmach == 0 { perr("'become' outside a machine") } + let m = mach_stk[nmach - 1] + let target: Node = ptr_null() + let i = 0 + while i < len(m.kids) { if streq(m.kids[i].s, st.s) { target = m.kids[i] } i = i + 1 } + if ptr_is_null(target) { perr(sconcat("become: no state ", st.s)) } + let regv = emit_expr(m.a) + let sv = emit_expr(target.b) + emit(" call void @fn_rt_setreg(i32 ") emit(regv.code) emit(", i32 ") emit(sv.code) emit(")\n") +} diff --git a/selfhost/emit_math.ludic b/selfhost/emit_math.ludic new file mode 100644 index 00000000..00462c0a --- /dev/null +++ b/selfhost/emit_math.ludic @@ -0,0 +1,29 @@ +# emit_math.ludic — the math builtins that lower to inline IR rather than a +# runtime call: min, max, abs, clamp. Everything else named like a builtin +# (clear, fill_rect, reg, ...) is resolved to its rt_ function by emit_call. + +fn is_math_builtin(name: ptr) -> bool { + return streq(name,"min") or streq(name,"max") or streq(name,"abs") or streq(name,"clamp") +} + +fn emit_math_builtin(name: ptr, e: Node) -> Val { + if streq(name, "abs") { + let a = emit_expr(e.kids[0]) + let c = emit_bind(sconcat("icmp slt i32 ", sconcat(a.code, ", 0"))) + let n = emit_bind(sconcat("sub i32 0, ", a.code)) + return val(emit_bind(sconcat("select i1 ", sconcat(c, sconcat(", i32 ", sconcat(n, sconcat(", i32 ", a.code)))))), "int") + } + if streq(name, "min") or streq(name, "max") { + let a = emit_expr(e.kids[0]) let b = emit_expr(e.kids[1]) + let op = "slt" + if streq(name, "max") { op = "sgt" } + let c = emit_bind(sconcat("icmp ", sconcat(op, sconcat(" i32 ", sconcat(a.code, sconcat(", ", b.code)))))) + return val(emit_bind(sconcat("select i1 ", sconcat(c, sconcat(", i32 ", sconcat(a.code, sconcat(", i32 ", b.code)))))), "int") + } + # clamp(v, lo, hi) = max(lo, min(v, hi)) + let v = emit_expr(e.kids[0]) let lo = emit_expr(e.kids[1]) let hi = emit_expr(e.kids[2]) + let c1 = emit_bind(sconcat("icmp slt i32 ", sconcat(v.code, sconcat(", ", hi.code)))) + let t = emit_bind(sconcat("select i1 ", sconcat(c1, sconcat(", i32 ", sconcat(v.code, sconcat(", i32 ", hi.code)))))) + let c2 = emit_bind(sconcat("icmp sgt i32 ", sconcat(lo.code, sconcat(", ", t)))) + return val(emit_bind(sconcat("select i1 ", sconcat(c2, sconcat(", i32 ", sconcat(lo.code, sconcat(", i32 ", t)))))), "int") +} diff --git a/selfhost/emit_new.ludic b/selfhost/emit_new.ludic new file mode 100644 index 00000000..7f139f19 --- /dev/null +++ b/selfhost/emit_new.ludic @@ -0,0 +1,88 @@ +# emit_new.ludic — heap construction and slice operations: `new S`, `new []T`, +# push(slice, v) and len(slice). Slices are a { data, len, cap } header the +# holder points at, so growth is visible to every holder. + +fn emit_sizeof(llt: ptr) -> ptr { + let p = emit_bind(sconcat("getelementptr ", sconcat(llt, ", ptr null, i32 1"))) + return emit_bind(sconcat("ptrtoint ptr ", sconcat(p, " to i64"))) +} + +fn emit_new_struct(name: ptr) -> Val { + let s = find_struct(name) + if ptr_is_null(s) { perr("unknown struct in new") } + let sz = emit_sizeof(sconcat("%Str_", name)) + let obj = emit_bind(sconcat("call ptr @malloc(i64 ", sconcat(sz, ")"))) + let f = 0 + while f < len(s.kids) { + let fd = s.kids[f] + let addr = nreg() + emit(" ") emit(addr) emit(" = getelementptr inbounds %Str_") emit(name) + emit(", ptr ") emit(obj) emit(", i32 0, i32 ") emit(itoa(f)) emit("\n") + let lt = llty(fd.ty) + let v = "0" + if streq(lt, "ptr") { v = "null" } + if not ptr_is_null(fd.a) { let dv = emit_expr(fd.a) v = dv.code } + emit(" store ") emit(lt) emit(" ") emit(v) emit(", ptr ") emit(addr) emit("\n") + f = f + 1 + } + return val(obj, name) +} + +fn emit_new_slice(ty: ptr) -> Val { + let sz = emit_sizeof("%LSlice") + let h = emit_bind(sconcat("call ptr @malloc(i64 ", sconcat(sz, ")"))) + let d0 = nreg() emit(" ") emit(d0) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) emit(", i32 0, i32 0\n") + emit(" store ptr null, ptr ") emit(d0) emit("\n") + let d1 = nreg() emit(" ") emit(d1) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) emit(", i32 0, i32 1\n") + emit(" store i32 0, ptr ") emit(d1) emit("\n") + let d2 = nreg() emit(" ") emit(d2) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) emit(", i32 0, i32 2\n") + emit(" store i32 0, ptr ") emit(d2) emit("\n") + return val(h, ty) +} + +fn slice_field(h: ptr, i: int) -> ptr { + let r = nreg() + emit(" ") emit(r) emit(" = getelementptr inbounds %LSlice, ptr ") emit(h) + emit(", i32 0, i32 ") emit(itoa(i)) emit("\n") + return r +} + +fn emit_len(e: Node) -> Val { + let s = emit_expr(e.kids[0]) + let lp = slice_field(s.code, 1) + return val(emit_bind(sconcat("load i32, ptr ", lp)), "int") +} + +fn emit_push(e: Node) -> Val { + let s = emit_expr(e.kids[0]) + let el = slice_elem(s.ty) + let elt = llty(el) + let h = s.code + let lp = slice_field(h, 1) let cp = slice_field(h, 2) let dp = slice_field(h, 0) + let l = emit_bind(sconcat("load i32, ptr ", lp)) + let c = emit_bind(sconcat("load i32, ptr ", cp)) + let full = emit_bind(sconcat("icmp sge i32 ", sconcat(l, sconcat(", ", c)))) + let grow = lbl("grow") let put = lbl("put") + emit(" br i1 ") emit(full) emit(", label %") emit(grow) emit(", label %") emit(put) emit("\n") + emit(grow) emit(":\n") + let dbl = emit_bind(sconcat("mul i32 ", sconcat(c, ", 2"))) + let isz = emit_bind(sconcat("icmp eq i32 ", sconcat(c, ", 0"))) + let nc = emit_bind(sconcat("select i1 ", sconcat(isz, sconcat(", i32 8, i32 ", dbl)))) + let esz = emit_sizeof(elt) + let ncw = emit_bind(sconcat("zext i32 ", sconcat(nc, " to i64"))) + let bytes = emit_bind(sconcat("mul i64 ", sconcat(ncw, sconcat(", ", esz)))) + let old = emit_bind(sconcat("load ptr, ptr ", dp)) + let nd = emit_bind(sconcat("call ptr @realloc(ptr ", sconcat(old, sconcat(", i64 ", sconcat(bytes, ")"))))) + emit(" store ptr ") emit(nd) emit(", ptr ") emit(dp) emit("\n") + emit(" store i32 ") emit(nc) emit(", ptr ") emit(cp) emit("\n") + emit(" br label %") emit(put) emit("\n") + emit(put) emit(":\n") + let v = emit_expr(e.kids[1]) + let data = emit_bind(sconcat("load ptr, ptr ", dp)) + let slot = nreg() + emit(" ") emit(slot) emit(" = getelementptr inbounds ") emit(elt) emit(", ptr ") emit(data) emit(", i32 ") emit(l) emit("\n") + emit(" store ") emit(elt) emit(" ") emit(v.code) emit(", ptr ") emit(slot) emit("\n") + let l1 = emit_bind(sconcat("add i32 ", sconcat(l, ", 1"))) + emit(" store i32 ") emit(l1) emit(", ptr ") emit(lp) emit("\n") + return val("0", "void") +} diff --git a/selfhost/emit_query.ludic b/selfhost/emit_query.ludic new file mode 100644 index 00000000..8a5931ff --- /dev/null +++ b/selfhost/emit_query.ludic @@ -0,0 +1,98 @@ +# emit_query.ludic — the ECS query loop. Iterates live entities, filters by the +# components/archetypes each carries, binds the requested components, and runs +# the body once per match. Mirrors ll_query in compiler/back/ir_ecs.c. + +fn find_arch_id(name: ptr) -> int { + let i = 0 let n = 1 + while i < len(prog) { if prog[i].kind == N_ARCH { if streq(prog[i].s, name) { return n } n = n + 1 } i = i + 1 } + return 0 +} + +fn emit_query(st: Node) -> void { + let me = itoa(MAX_ENT) + let ip = emit_alloca("i32") + store_at("i32", "0", ip) + if nself < len(self_stk) { self_stk[nself] = ip } else { push(self_stk, ip) } + nself = nself + 1 + + let cond = lbl("qcond") let body = lbl("qbody") let nxt = lbl("qnext") let endl = lbl("qend") + emit(" br label %") emit(cond) emit("\n") + emit(cond) emit(":\n") + let i0 = emit_bind(sconcat("load i32, ptr ", ip)) + let ec = emit_bind("load i32, ptr @L_entc") + let lt = emit_bind(sconcat("icmp slt i32 ", sconcat(i0, sconcat(", ", ec)))) + emit(" br i1 ") emit(lt) emit(", label %") emit(body) emit(", label %") emit(endl) emit("\n") + emit(body) emit(":\n") g_term = false + let i1 = emit_bind(sconcat("load i32, ptr ", ip)) + # alive? + let ap = nreg() emit(" ") emit(ap) emit(" = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_alive, i32 0, i32 ") emit(i1) emit("\n") + let al = emit_bind(sconcat("load i32, ptr ", ap)) + let alc = emit_bind(sconcat("icmp ne i32 ", sconcat(al, ", 0"))) + let ka = lbl("qa") + emit(" br i1 ") emit(alc) emit(", label %") emit(ka) emit(", label %") emit(nxt) emit("\n") + emit(ka) emit(":\n") + + let terms = st.c + # component / archetype filters + let t = 0 + while t < len(terms.kids) { + let tm = terms.kids[t] + let ak = find_arch_id(tm.s) + let ok = "0" + if ak > 0 { + let kp = nreg() emit(" ") emit(kp) emit(" = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_kind, i32 0, i32 ") emit(i1) emit("\n") + let kv = emit_bind(sconcat("load i32, ptr ", kp)) + ok = emit_bind(sconcat("icmp eq i32 ", sconcat(kv, sconcat(", ", itoa(ak))))) + } else { + let hp = nreg() emit(" ") emit(hp) emit(" = getelementptr inbounds [") emit(me) emit(" x i8], ptr @H_") emit(tm.s) emit(", i32 0, i32 ") emit(i1) emit("\n") + let hv = emit_bind(sconcat("load i8, ptr ", hp)) + ok = emit_bind(sconcat("icmp ne i8 ", sconcat(hv, ", 0"))) + } + let keep = lbl("qt") + emit(" br i1 ") emit(ok) emit(", label %") emit(keep) emit(", label %") emit(nxt) emit("\n") + emit(keep) emit(":\n") + t = t + 1 + } + + # bind the requested components to the loop variables, in order + let save = nloc + let vi = 0 + t = 0 + while t < len(terms.kids) { + let tm = terms.kids[t] + if tm.ival == 0 and find_arch_id(tm.s) == 0 { + if vi < len(st.kids) { + let slot = nreg() + emit(" ") emit(slot) emit(" = getelementptr inbounds [") emit(me) emit(" x %Cmp_") emit(tm.s) emit("], ptr @S_") emit(tm.s) emit(", i32 0, i32 ") emit(i1) emit("\n") + let vslot = emit_alloca("ptr") + emit(" store ptr ") emit(slot) emit(", ptr ") emit(vslot) emit("\n") + loc_push(st.kids[vi].s, vslot, tm.s) + vi = vi + 1 + } + } + t = t + 1 + } + + # optional where-clause + if not ptr_is_null(st.b) { + let w = emit_expr(st.b) + let wc = emit_bind(sconcat("icmp ne i32 ", sconcat(w.code, ", 0"))) + let kw = lbl("qw") + emit(" br i1 ") emit(wc) emit(", label %") emit(kw) emit(", label %") emit(nxt) emit("\n") + emit(kw) emit(":\n") + } + + loop_push(nxt, endl) + emit_block(st.a) + loop_pop() + nloc = save + if not g_term { emit(" br label %") emit(nxt) emit("\n") } + + emit(nxt) emit(":\n") + let i2 = emit_bind(sconcat("load i32, ptr ", ip)) + let i3 = emit_bind(sconcat("add i32 ", sconcat(i2, ", 1"))) + store_at("i32", i3, ip) + emit(" br label %") emit(cond) emit("\n") + emit(endl) emit(":\n") g_term = false + nself = nself - 1 +} diff --git a/selfhost/emit_save.ludic b/selfhost/emit_save.ludic new file mode 100644 index 00000000..7a170f85 --- /dev/null +++ b/selfhost/emit_save.ludic @@ -0,0 +1,61 @@ +# emit_save.ludic — save() / load() snapshot of the whole ECS world. The +# compiler writes the entity/component half itself (it knows the shape) and +# hands the open file to rt_save_state/rt_load_state for the runtime's own +# state. Mirrors compiler/back/ir_save.c. save()->@L_save, load()->@L_load. + +var g_iok: int = 0 + +fn emit_io(fn2: ptr, p: ptr, bytes: ptr) -> void { + let r = sconcat("%io", itoa(g_iok)) g_iok = g_iok + 1 + emit(" ") emit(r) emit(" = call i64 @") emit(fn2) emit("(ptr ") emit(p) emit(", i64 1, i64 ") emit(bytes) emit(", ptr %f)\n") +} + +fn emit_snapshot_blocks(fn2: ptr) -> void { + g_iok = 0 + let me = itoa(MAX_ENT) + emit_io(fn2, "@L_entc", "4") + emit_io(fn2, "@L_freen", "4") + emit(" %nalive = mul i64 ") emit(me) emit(", 4\n") + emit_io(fn2, "@L_alive", "%nalive") + emit_io(fn2, "@L_freelist", "%nalive") + emit_io(fn2, "@L_kind", "%nalive") + let i = 0 + while i < len(prog) { if prog[i].kind == N_VAR { emit_io(fn2, sconcat("@g_", prog[i].s), "4") } i = i + 1 } + let ci = 0 + i = 0 + while i < len(prog) { + if prog[i].kind == N_COMP { + let c = prog[i].s + let csz = sconcat("%csz", itoa(ci)) + emit(" ") emit(csz) emit(" = ptrtoint ptr getelementptr (%Cmp_") emit(c) emit(", ptr null, i32 ") emit(me) emit(") to i64\n") + emit_io(fn2, sconcat("@S_", c), csz) + emit_io(fn2, sconcat("@H_", c), me) + ci = ci + 1 + } + i = i + 1 + } +} + +fn emit_snapshot() -> void { + emith("@.sav_path = private unnamed_addr constant [10 x i8] c\"ludic.sav\\00\"\n") + emith("@.sav_wb = private unnamed_addr constant [3 x i8] c\"wb\\00\"\n") + emith("@.sav_rb = private unnamed_addr constant [3 x i8] c\"rb\\00\"\n") + let has_save = not ptr_is_null(find_fn("rt_save_state")) + let has_load = not ptr_is_null(find_fn("rt_load_state")) + + emit("define void @L_save() {\nentry:\n") + emit(" %f = call ptr @fopen(ptr @.sav_path, ptr @.sav_wb)\n") + emit(" %bad = icmp eq ptr %f, null\n") + emit(" br i1 %bad, label %out, label %go\ngo:\n") + emit_snapshot_blocks("fwrite") + if has_save { emit(" call void @fn_rt_save_state(ptr %f)\n") } + emit(" %c = call i32 @fclose(ptr %f)\n br label %out\nout:\n ret void\n}\n\n") + + emit("define i32 @L_load() {\nentry:\n") + emit(" %f = call ptr @fopen(ptr @.sav_path, ptr @.sav_rb)\n") + emit(" %bad = icmp eq ptr %f, null\n") + emit(" br i1 %bad, label %miss, label %go\nmiss:\n ret i32 0\ngo:\n") + emit_snapshot_blocks("fread") + if has_load { emit(" call void @fn_rt_load_state(ptr %f)\n") } + emit(" %c = call i32 @fclose(ptr %f)\n ret i32 1\n}\n\n") +} diff --git a/selfhost/emit_spawn.ludic b/selfhost/emit_spawn.ludic new file mode 100644 index 00000000..a418bcba --- /dev/null +++ b/selfhost/emit_spawn.ludic @@ -0,0 +1,68 @@ +# emit_spawn.ludic — spawn / despawn / self(), and seeding a component's fields +# from its declared defaults plus any per-spawn overrides. + +fn emit_init_component(e: ptr, comp: ptr, rec: Node) -> void { + let me = itoa(MAX_ENT) + let c = find_comp(comp) + if ptr_is_null(c) { perr(sconcat("spawn: unknown component ", comp)) } + let hp = nreg() emit(" ") emit(hp) emit(" = getelementptr inbounds [") emit(me) emit(" x i8], ptr @H_") emit(comp) emit(", i32 0, i32 ") emit(e) emit("\n") + emit(" store i8 1, ptr ") emit(hp) emit("\n") + let slot = nreg() + emit(" ") emit(slot) emit(" = getelementptr inbounds [") emit(me) emit(" x %Cmp_") emit(comp) emit("], ptr @S_") emit(comp) emit(", i32 0, i32 ") emit(e) emit("\n") + # defaults + let f = 0 + while f < len(c.kids) { + let fd = c.kids[f] + let addr = nreg() + emit(" ") emit(addr) emit(" = getelementptr inbounds %Cmp_") emit(comp) emit(", ptr ") emit(slot) emit(", i32 0, i32 ") emit(itoa(f)) emit("\n") + let lt = llty(fd.ty) + let v = "0" + if streq(lt, "ptr") { v = "null" } + if not ptr_is_null(fd.a) { let dv = emit_expr(fd.a) v = dv.code } + emit(" store ") emit(lt) emit(" ") emit(v) emit(", ptr ") emit(addr) emit("\n") + f = f + 1 + } + # per-spawn overrides + if not ptr_is_null(rec) { + let j = 0 + while j < len(rec.kids) { + let fi = rec.kids[j] + let fidx = field_index(c, fi.s) + if fidx >= 0 { + let addr = nreg() + emit(" ") emit(addr) emit(" = getelementptr inbounds %Cmp_") emit(comp) emit(", ptr ") emit(slot) emit(", i32 0, i32 ") emit(itoa(fidx)) emit("\n") + let dv = emit_expr(fi.a) + emit(" store ") emit(llty(field_type(c, fi.s))) emit(" ") emit(dv.code) emit(", ptr ") emit(addr) emit("\n") + } + j = j + 1 + } + } +} + +fn emit_spawn(st: Node) -> void { + let e = emit_bind("call i32 @L_alloc()") + let ak = find_arch_id(st.s) + if ak > 0 { + let me = itoa(MAX_ENT) + let kp = nreg() emit(" ") emit(kp) emit(" = getelementptr inbounds [") emit(me) emit(" x i32], ptr @L_kind, i32 0, i32 ") emit(e) emit("\n") + emit(" store i32 ") emit(itoa(ak)) emit(", ptr ") emit(kp) emit("\n") + let arch = find_arch(st.s) + let c = 0 + while c < len(arch.kids) { + let cn = arch.kids[c].s + let rec = ptr_null() + let i = 0 + while i < len(st.kids) { if streq(st.kids[i].s, cn) { rec = st.kids[i].a } i = i + 1 } + emit_init_component(e, cn, rec) + c = c + 1 + } + } else { + let i = 0 + while i < len(st.kids) { emit_init_component(e, st.kids[i].s, st.kids[i].a) i = i + 1 } + } +} + +fn emit_despawn(st: Node) -> void { + let v = emit_expr(st.a) + emit(" call void @L_free_entity(i32 ") emit(v.code) emit(")\n") +} diff --git a/selfhost/emit_stmt.ludic b/selfhost/emit_stmt.ludic new file mode 100644 index 00000000..4643e01b --- /dev/null +++ b/selfhost/emit_stmt.ludic @@ -0,0 +1,193 @@ +# emit_stmt.ludic — lower statements. Terminators set g_term so the rest of a +# block is skipped until a new basic block opens. + +fn emit_block(b: Node) -> void { + let i = 0 + while i < len(b.kids) { + if g_term { return } + emit_stmt(b.kids[i]) + i = i + 1 + } +} + +# store `val` (llvm type `lt`) into address `addr` +fn store_at(lt: ptr, v: ptr, addr: ptr) -> void { + emit(" store ") emit(lt) emit(" ") emit(v) emit(", ptr ") emit(addr) emit("\n") +} + +fn emit_assign(st: Node) -> void { + # resolve the target's address and type + let t = st.a + let addr = "0" + let ty = "int" + if t.kind == E_ID { + let li = loc_find(t.s) + if li >= 0 { addr = loc_reg[li] ty = loc_ty[li] } + else { + let g = find_global(t.s) + if ptr_is_null(g) { perr(sconcat("assign to unknown ", t.s)) } + addr = sconcat("@g_", t.s) ty = g.ty + } + } else { + if t.kind == E_MEMBER { addr = emit_member_addr(t) ty = g_addr_ty } + else { if t.kind == E_INDEX { addr = emit_index_addr(t) ty = g_addr_ty } + else { perr("bad assignment target") } } + } + let lt = llty(ty) + let rv = emit_expr(st.b) + let v = rv.code + if not streq(st.s, "=") { + let cur = emit_bind(sconcat("load ", sconcat(lt, sconcat(", ptr ", addr)))) + let opc = "add" + if streq(st.s, "-=") { opc = "sub" } + if streq(st.s, "*=") { opc = "mul" } + if streq(st.s, "/=") { opc = "sdiv" } + v = emit_bind(sconcat(opc, sconcat(" i32 ", sconcat(cur, sconcat(", ", v))))) + } + store_at(lt, v, addr) +} + +fn emit_if(st: Node) -> void { + let c = emit_expr(st.a) + let cc = emit_bind(sconcat("icmp ne i32 ", sconcat(c.code, ", 0"))) + let has_else = not ptr_is_null(st.c) + let tl = lbl("then") let el = lbl("else") let en = lbl("ifend") + if has_else { emit(" br i1 ") emit(cc) emit(", label %") emit(tl) emit(", label %") emit(el) emit("\n") } + else { emit(" br i1 ") emit(cc) emit(", label %") emit(tl) emit(", label %") emit(en) emit("\n") } + emit(tl) emit(":\n") g_term = false + emit_block(st.b) + if not g_term { emit(" br label %") emit(en) emit("\n") } + if has_else { + emit(el) emit(":\n") g_term = false + # else is either a block or a nested if-statement + if st.c.kind == S_IF { emit_stmt(st.c) } else { emit_block(st.c) } + if not g_term { emit(" br label %") emit(en) emit("\n") } + } + emit(en) emit(":\n") g_term = false +} + +fn emit_while(st: Node) -> void { + let cl = lbl("wcond") let bl = lbl("wbody") let en = lbl("wend") + emit(" br label %") emit(cl) emit("\n") + emit(cl) emit(":\n") + let c = emit_expr(st.a) + let cc = emit_bind(sconcat("icmp ne i32 ", sconcat(c.code, ", 0"))) + emit(" br i1 ") emit(cc) emit(", label %") emit(bl) emit(", label %") emit(en) emit("\n") + emit(bl) emit(":\n") g_term = false + loop_push(cl, en) + emit_block(st.b) + loop_pop() + if not g_term { emit(" br label %") emit(cl) emit("\n") } + emit(en) emit(":\n") g_term = false +} + +fn emit_for(st: Node) -> void { + let slot = emit_alloca("i32") + let lo = emit_expr(st.a) + store_at("i32", lo.code, slot) + loc_push(st.s, slot, "int") + let cl = lbl("fcond") let bl = lbl("fbody") let ct = lbl("fcont") let en = lbl("fend") + emit(" br label %") emit(cl) emit("\n") + emit(cl) emit(":\n") + let iv = emit_bind(sconcat("load i32, ptr ", slot)) + let hi = emit_expr(st.b) + let cc = emit_bind(sconcat("icmp slt i32 ", sconcat(iv, sconcat(", ", hi.code)))) + emit(" br i1 ") emit(cc) emit(", label %") emit(bl) emit(", label %") emit(en) emit("\n") + emit(bl) emit(":\n") g_term = false + loop_push(ct, en) + emit_block(st.c) + loop_pop() + if not g_term { emit(" br label %") emit(ct) emit("\n") } + emit(ct) emit(":\n") + let i2 = emit_bind(sconcat("load i32, ptr ", slot)) + let i3 = emit_bind(sconcat("add i32 ", sconcat(i2, ", 1"))) + store_at("i32", i3, slot) + emit(" br label %") emit(cl) emit("\n") + emit(en) emit(":\n") g_term = false +} + +fn emit_return(st: Node) -> void { + if not ptr_is_null(st.a) { + let v = emit_expr(st.a) + store_at(llty(ret_ty), v.code, "%retval") + } + emit(" br label %ret\n") + g_term = true +} + +fn arm_is_default(arm: Node) -> bool { + let p = 0 + while p < len(arm.kids) { if arm.kids[p].kind == E_ID and streq(arm.kids[p].s, "_") { return true } p = p + 1 } + return false +} + +fn emit_match(st: Node) -> void { + let sv = emit_expr(st.a) + let endl = lbl("mend") + let deflt: Node = ptr_null() + let i = 0 + while i < len(st.kids) { + let arm = st.kids[i] + if arm_is_default(arm) { deflt = arm } + else { + let acc = "0" + let first = true + let p = 0 + while p < len(arm.kids) { + let pv = emit_expr(arm.kids[p]) + let c = emit_bind(sconcat("icmp eq i32 ", sconcat(sv.code, sconcat(", ", pv.code)))) + if first { acc = c first = false } + else { acc = emit_bind(sconcat("or i1 ", sconcat(acc, sconcat(", ", c)))) } + p = p + 1 + } + let bodyl = lbl("mbody") let nextl = lbl("marm") + emit(" br i1 ") emit(acc) emit(", label %") emit(bodyl) emit(", label %") emit(nextl) emit("\n") + emit(bodyl) emit(":\n") g_term = false + emit_block(arm.a) + if not g_term { emit(" br label %") emit(endl) emit("\n") } + emit(nextl) emit(":\n") g_term = false + } + i = i + 1 + } + if not ptr_is_null(deflt) { emit_block(deflt.a) } + if not g_term { emit(" br label %") emit(endl) emit("\n") } + emit(endl) emit(":\n") g_term = false +} + +fn emit_stmt(st: Node) -> void { + if st.kind == S_LET { + let ty = st.ty + if ptr_is_null(ty) { let v0 = emit_expr(st.a) ty = v0.ty + let slot = emit_alloca(llty(ty)) store_at(llty(ty), v0.code, slot) loc_push(st.s, slot, ty) return } + let slot = emit_alloca(llty(ty)) + if ptr_is_null(st.a) { + let z = "0" + if streq(llty(ty), "ptr") { z = "null" } + store_at(llty(ty), z, slot) + } else { let v = emit_expr(st.a) store_at(llty(ty), v.code, slot) } + loc_push(st.s, slot, ty) + return + } + if st.kind == S_ASSIGN { emit_assign(st) return } + if st.kind == S_IF { emit_if(st) return } + if st.kind == S_WHILE { emit_while(st) return } + if st.kind == S_FOR { emit_for(st) return } + if st.kind == S_RETURN { emit_return(st) return } + if st.kind == S_BREAK { emit(" br label %") emit(brk_lbl[nloop - 1]) emit("\n") g_term = true return } + if st.kind == S_CONTINUE { emit(" br label %") emit(cnt_lbl[nloop - 1]) emit("\n") g_term = true return } + if st.kind == S_MATCH { emit_match(st) return } + if st.kind == S_QUERY { emit_query(st) return } + if st.kind == S_SPAWN { emit_spawn(st) return } + if st.kind == S_DESPAWN { emit_despawn(st) return } + if st.kind == S_MACHINE { emit_machine(st) return } + if st.kind == S_BECOME { emit_become(st) return } + if st.kind == S_EXPR { let v = emit_expr(st.a) return } + perr("cannot emit statement") +} + +fn loop_push(cont: ptr, brk: ptr) -> void { + if nloop < len(cnt_lbl) { cnt_lbl[nloop] = cont brk_lbl[nloop] = brk } + else { push(cnt_lbl, cont) push(brk_lbl, brk) } + nloop = nloop + 1 +} +fn loop_pop() -> void { nloop = nloop - 1 } diff --git a/selfhost/emit_ui.ludic b/selfhost/emit_ui.ludic new file mode 100644 index 00000000..ef2c5841 --- /dev/null +++ b/selfhost/emit_ui.ludic @@ -0,0 +1,125 @@ +# emit_ui.ludic — a `ui` block is data: the compiler flattens the widget tree +# and emits @ui_build(), which hands every property to the Ludic UI runtime via +# rt_ui_set(index, key, value). Mirrors compiler/back/ir_ui.c. Layout/drawing/ +# focus all live in runtime/native/ui.ludic. + +var uiw: []Node # flattened widgets, pre-order +var uiw_parent: []int +var ui_roots: []int # first-widget index of each ui block + +fn ui_wtype(w: Node) -> int { + let s = w.s + if streq(s, "panel") { return 0 } if streq(s, "col") { return 1 } if streq(s, "row") { return 2 } + if streq(s, "label") { return 3 } if streq(s, "button") { return 4 } + if streq(s, "image") { return 5 } if streq(s, "spacer") { return 6 } + return 0 +} +fn ui_prop(w: Node, key: ptr) -> Node { + let i = 0 + while i < len(w.b.kids) { if streq(w.b.kids[i].s, key) { return w.b.kids[i].a } i = i + 1 } + return ptr_null() +} +fn ui_flatten(w: Node, parent: int) -> void { + let idx = len(uiw) + push(uiw, w) push(uiw_parent, parent) + let i = 0 + while i < len(w.kids) { ui_flatten(w.kids[i], idx) i = i + 1 } +} +fn ui_flatten_all() -> void { + uiw = new []Node uiw_parent = new []int ui_roots = new []int + let i = 0 + while i < len(prog) { + if prog[i].kind == N_UI and prog[i].ival == 1 { push(ui_roots, len(uiw)) ui_flatten(prog[i].a, 0 - 1) } + i = i + 1 + } +} +fn has_ui() -> bool { + let i = 0 + while i < len(prog) { if prog[i].kind == N_UI and prog[i].ival == 1 { return true } i = i + 1 } + return false +} + +# index of a UI_: a ui block's root, or a widget's id= +fn ui_index_of(nm: ptr) -> int { + let s = substr(nm, 3, slen(nm) - 3) # strip "UI_" + let u = 0 let bi = 0 + let i = 0 + while i < len(prog) { + if prog[i].kind == N_UI and prog[i].ival == 1 { if streq(prog[i].s, s) { return ui_roots[bi] } bi = bi + 1 } + i = i + 1 + } + i = 0 + while i < len(uiw) { + let idp = ui_prop(uiw[i], "id") + if not ptr_is_null(idp) { if idp.kind == E_ID and streq(idp.s, s) { return i } } + i = i + 1 + } + return 0 +} +fn is_ui_ident(nm: ptr) -> bool { + return slen(nm) > 3 and peek8(nm, 0) == 85 and peek8(nm, 1) == 73 and peek8(nm, 2) == 95 # "UI_" +} + +fn ll_ui_set(idx: int, key: int, val: ptr) -> void { + emit(" call void @fn_rt_ui_set(i32 ") emit(itoa(idx)) emit(", i32 ") emit(itoa(key)) emit(", i32 ") emit(val) emit(")\n") +} +fn ui_prop_key(k: ptr) -> int { + if streq(k,"w") { return 2 } if streq(k,"h") { return 3 } if streq(k,"x") { return 4 } if streq(k,"y") { return 5 } + if streq(k,"pad") { return 7 } if streq(k,"gap") { return 8 } if streq(k,"bg") { return 9 } if streq(k,"fg") { return 10 } + if streq(k,"border") { return 11 } if streq(k,"grow") { return 13 } if streq(k,"font") { return 14 } if streq(k,"size") { return 15 } + if streq(k,"inset") { return 16 } if streq(k,"focus") { return 17 } + return 0 - 1 +} + +fn emit_ui_build() -> void { + ui_flatten_all() + ll_t = 0 ll_lbl = 0 g_term = false loc_reset() nloop = 0 + let fbody = buf_new() + falloc = buf_new() + let saved = code + code = fbody + emit(" call void @fn_rt_ui_reset(i32 ") emit(itoa(len(uiw))) emit(")\n") + let i = 0 + while i < len(uiw) { + let w = uiw[i] + let t = ui_wtype(w) + ll_ui_set(i, 0, itoa(t)) + ll_ui_set(i, 1, itoa(uiw_parent[i])) + if t == 4 { ll_ui_set(i, 17, "1") } + let p = 0 + while p < len(w.b.kids) { + let pr = w.b.kids[p] + let k = pr.s + let v = pr.a + if streq(k, "id") { p = p + 1 continue } + if streq(k, "text") { + let sv = emit_expr(v) + emit(" call void @fn_rt_ui_static_text(i32 ") emit(itoa(i)) emit(", ptr ") emit(sv.code) emit(")\n") + } else { if streq(k, "skin") or streq(k, "image") { + let sv = emit_expr(v) + let r = emit_bind(sconcat("call i32 @fn_rt_image_load(ptr ", sconcat(sv.code, ")"))) + if streq(k, "skin") { ll_ui_set(i, 20, r) } else { ll_ui_set(i, 19, r) } + } else { if streq(k, "align") { + if v.kind == E_ID { + let a = 0 + if streq(v.s, "center") { a = 1 } if streq(v.s, "end") { a = 2 } + ll_ui_set(i, 12, itoa(a)) + } else { let vv = emit_expr(v) ll_ui_set(i, 12, vv.code) } + } else { + let key = ui_prop_key(k) + if key >= 0 { + let vv = emit_expr(v) + ll_ui_set(i, key, vv.code) + if key == 4 or key == 5 { ll_ui_set(i, 6, "1") } + } + } } } + p = p + 1 + } + i = i + 1 + } + code = saved + emit("define void @ui_build() {\nentry:\n") + emit(buf_str(falloc)) + emit(buf_str(fbody)) + emit(" ret void\n}\n\n") +} diff --git a/selfhost/game-build.sh b/selfhost/game-build.sh new file mode 100755 index 00000000..fc321288 --- /dev/null +++ b/selfhost/game-build.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# game-build.sh — compile a Ludic GAME with the self-hosted compiler. The +# compiler resolves the game's own `import`s and auto-splices the Ludic runtime +# (runtime/native/core.ludic + its imports), exactly as the C compiler does. +# Headless only for now (renders to out.ppm). Run from the repo root. +# ./selfhost/game-build.sh +set -u +cd "$(dirname "$0")/.." +SH="$1"; GAME="$2"; OUT="$3" +CC="${LUDIC_CC:-clang}" +ERR="$(mktemp)" +"$SH" "$GAME" > "$OUT.ll" 2>"$ERR" || { echo "self-host failed:"; head -5 "$ERR"; rm -f "$ERR"; exit 1; } +# -O2 removes the dead windowing branches (is_windowed()==0) so win_* need no defs +$CC -O2 "$OUT.ll" -o "$OUT" 2>"$ERR" || { echo "link failed:"; grep -i error "$ERR" | head -5; rm -f "$ERR"; exit 1; } +rm -f "$ERR" "$OUT.ll" # keep only the binary +echo "built $OUT" diff --git a/selfhost/golden/chronorift.ppm b/selfhost/golden/chronorift.ppm new file mode 100644 index 00000000..0a242d95 --- /dev/null +++ b/selfhost/golden/chronorift.ppm @@ -0,0 +1,4 @@ +P6 +320 240 +255 +$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿÿÿÿÿÿÿ$.$.ÿÿÿ$.$.$.$.$.$.ÿÿÿÿÿÿÿÿÿ$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿÿÿÿ$.ÿÿÿÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿ$.$.$.$.$.ÿÿÿ$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿ$.ÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿÿÿÿÿÿÿ$.$.ÿÿÿ$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿ$.ÿÿÿ$.ÿÿÿÿÿÿÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.ÿÿÿÿÿÿÿÿÿ$.$.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$.$.ÿÿÿÿÿÿÿÿÿ$.$.ÿÿÿ$.$.$.ÿÿÿ$.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@à@@$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³iÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔiÿÔCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•j?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³%•j%•j%•j%•j%•jCá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³Cá³?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ                                                                                                                                                                                                                                   ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                  ÿàŠÿàŠÿàŠÿàŠ    ÿàŠ         ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ  ÿàŠÿàŠÿàŠ   ÿàŠÿàŠÿàŠ  ÿàŠ   ÿàŠ ÿàŠÿàŠÿàŠÿàŠÿàŠ                                                            ::U::U   ÿÿ                                     ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ  ÿàŠÿàŠÿàŠ   ÿàŠÿàŠÿàŠ  ÿàŠ   ÿàŠ ÿàŠÿàŠÿàŠÿàŠÿàŠ              ÿÿ                                          É ÿ   É ÿ  É ÿÉ ÿÉ ÿ   É ÿÉ ÿÉ ÿ  É ÿÉ ÿÉ ÿÉ ÿÉ ÿ                                                 ÿàŠ   ÿàŠ  ÿàŠÿàŠ         ÿàŠ  ÿàŠ  ÿàŠÿàŠ  ÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ                                                              ::U::U   ÿÿ                                     ÿàŠ  ÿàŠ  ÿàŠÿàŠ  ÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ                ÿÿ                                          É ÿÉ ÿ É ÿÉ ÿ É ÿ   É ÿ É ÿ   É ÿ É ÿ                                                     ÿàŠ   ÿàŠ   ÿàŠ         ÿàŠ ÿàŠ   ÿàŠ ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ     ÿàŠ   ÿàŠ   ÿàŠ                                                              ::U::U   ÿÿ                                     ÿàŠ ÿàŠ   ÿàŠ ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ     ÿàŠ   ÿàŠ   ÿàŠ                ÿÿ            ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1                  É ÿ É ÿ É ÿ É ÿ   É ÿ É ÿ     É ÿ                                                     ÿàŠÿàŠÿàŠÿàŠ    ÿàŠ         ÿàŠÿàŠ    ÿàŠ ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ ÿàŠÿàŠÿàŠ ÿàŠÿàŠÿàŠÿàŠÿàŠ   ÿàŠ                                                              ::U::U   ÿÿ                                     ÿàŠÿàŠ    ÿàŠ ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ ÿàŠÿàŠÿàŠ ÿàŠÿàŠÿàŠÿàŠÿàŠ   ÿàŠ                ÿÿ            ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1                  É ÿ É ÿ É ÿ É ÿÉ ÿÉ ÿÉ ÿÉ ÿ É ÿ É ÿÉ ÿÉ ÿ É ÿÉ ÿÉ ÿ                                                   ÿàŠ       ÿàŠ         ÿàŠ ÿàŠ   ÿàŠ  ÿàŠÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ                                                              ::U::U   ÿÿ             ?&1?&1?&1?&1?&1?&1?&1?&1                ÿàŠ ÿàŠ   ÿàŠ  ÿàŠÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ                ÿÿ          ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1              É ÿ   É ÿ É ÿ   É ÿ É ÿ   É ÿ É ÿ                                                     ÿàŠ       ÿàŠ         ÿàŠ  ÿàŠ  ÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ                                                              ::U::U   ÿÿ             ?&1?&1?&1?&1?&1?&1?&1?&1                ÿàŠ  ÿàŠ  ÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ   ÿàŠ                ÿÿ          ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1              É ÿ   É ÿ É ÿ   É ÿ É ÿ   É ÿ É ÿ                                                     ÿàŠ      ÿàŠÿàŠÿàŠ        ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ  ÿàŠÿàŠÿàŠ   ÿàŠÿàŠÿàŠ  ÿàŠ   ÿàŠ   ÿàŠ                                                              ::U::U   ÿÿ         ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1            ÿàŠ   ÿàŠ ÿàŠ   ÿàŠ  ÿàŠÿàŠÿàŠ   ÿàŠÿàŠÿàŠ  ÿàŠ   ÿàŠ   ÿàŠ                ÿÿ        ?&1?&1?&1?&1?&1?&1›L£›L£›L£›L£›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1            É ÿ   É ÿ É ÿ   É ÿ  É ÿÉ ÿÉ ÿ  É ÿÉ ÿÉ ÿÉ ÿÉ ÿ                                                                                                                                                                  ::U::U   ÿÿ         ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1                                                             ÿÿ        ?&1?&1?&1?&1?&1?&1›L£›L£›L£›L£›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                                                                                                                                                     ::U::U   ÿÿ       ?&1?&1?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1?&1?&1                                                           ÿÿ        ?&1?&1?&1?&1›L£›L£?&1?&1›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                                                                                                                                                 ::U::U   ÿÿ       ?&1?&1?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1?&1?&1                                                           ÿÿ        ?&1?&1?&1?&1›L£›L£?&1?&1›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                                                                                                                                                 ::U::U   ÿÿ     ?&1?&1?&1?&1?&1?&1‹›´‹›´ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ‹›´‹›´?&1?&1?&1?&1?&1?&1                                                         ÿÿ        ?&1?&1?&1?&1?&1?&1?&1?&1›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                                       ÿÿÿÿÿÿÿÿÿ  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿ  ÿÿÿ   ÿÿÿ                                                                      ::U::U   ÿÿ     ?&1?&1?&1?&1?&1?&1‹›´‹›´ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ‹›´‹›´?&1?&1?&1?&1?&1?&1                                                         ÿÿ        ?&1?&1?&1?&1?&1?&1?&1?&1›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                                      ÿÿÿ   ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ   ÿÿÿ ÿÿÿ   ÿÿÿ ÿÿÿ  ÿÿÿ                                                                       ::U::U   ÿÿ     ?&1?&1?&1?&1R`|R`|‹›´‹›´ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ‹›´‹›´R`|R`|?&1?&1?&1?&1                                                         ÿÿ        ?&1?&1?&1?&1›L£›L£ÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvЛL£›L£?&1?&1?&1?&1                                                                                      ÿÿÿ   ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ   ÿÿÿ ÿÿÿ     ÿÿÿ ÿÿÿ                                                                        ::U::U   ÿÿ     ?&1?&1?&1?&1R`|R`|‹›´‹›´ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ‹›´‹›´R`|R`|?&1?&1?&1?&1        ˆÿˆ   ˆÿˆ ˆÿˆˆÿˆˆÿˆˆÿˆ             ÿÿÿ   ÿÿÿÿÿÿÿÿÿ                   ÿÿ        ?&1?&1?&1?&1›L£›L£ÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvÐÑvЛL£›L£?&1?&1?&1?&1      ˆÿˆ   ˆÿˆ ˆÿˆˆÿˆˆÿˆˆÿˆ           ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿ                                                  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ     ÿÿÿÿÿÿ                                                                         ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´?&1?&1?&1?&1        ˆÿˆ   ˆÿˆ ˆÿˆ   ˆÿˆ           ÿÿÿÿÿÿ  ÿÿÿ   ÿÿÿ                  ÿÿ        ?&1?&1?&1?&1ÑvÐÑvЛL£›L£?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1›L£›L£ÑvÐÑvÐ?&1?&1?&1?&1      ˆÿˆ   ˆÿˆ ˆÿˆ   ˆÿˆ         ÿÿÿ   ÿÿÿ ÿÿÿ                                                     ÿÿÿ   ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ   ÿÿÿ ÿÿÿ     ÿÿÿ ÿÿÿ                                                                        ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´?&1?&1?&1?&1        ˆÿˆ   ˆÿˆ ˆÿˆ   ˆÿˆ          ÿÿÿ ÿÿÿ  ÿÿÿ  ÿÿÿÿÿÿ                  ÿÿ        ?&1?&1?&1?&1ÑvÐÑvЛL£›L£?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1›L£›L£ÑvÐÑvÐ?&1?&1?&1?&1      ˆÿˆ   ˆÿˆ ˆÿˆ   ˆÿˆ             ÿÿÿ ÿÿÿ                                                     ÿÿÿ   ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ   ÿÿÿ ÿÿÿ   ÿÿÿ ÿÿÿ  ÿÿÿ                                                                       ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1?&1?&1        ˆÿˆˆÿˆˆÿˆˆÿˆˆÿˆ ˆÿˆˆÿˆˆÿˆˆÿˆ          ÿÿÿ  ÿÿÿ  ÿÿÿ ÿÿÿ ÿÿÿ                  ÿÿ        ?&1?&1?&1?&1›L£›L£‹›´‹›´÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚‹›´‹›´›L£›L£?&1?&1?&1?&1      ˆÿˆˆÿˆˆÿˆˆÿˆˆÿˆ ˆÿˆˆÿˆˆÿˆˆÿˆ            ÿÿÿÿÿÿ  ÿÿÿÿÿÿÿÿÿÿÿÿ                                                  ÿÿÿ   ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ   ÿÿÿ  ÿÿÿÿÿÿÿÿÿ  ÿÿÿ   ÿÿÿ                                                                      ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1?&1?&1        ˆÿˆ   ˆÿˆ ˆÿˆ             ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿ  ÿÿÿ                  ÿÿ        ?&1?&1?&1?&1›L£›L£‹›´‹›´÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚÷‚‹›´‹›´›L£›L£?&1?&1?&1?&1      ˆÿˆ   ˆÿˆ ˆÿˆ              ÿÿÿ    ÿÿÿ   ÿÿÿ                                                                                                                                                          ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1?&1?&1        ˆÿˆ   ˆÿˆ ˆÿˆ                ÿÿÿ  ÿÿÿ   ÿÿÿ                  ÿÿ        ?&1?&1?&1?&1?&1?&1‹›´‹›´÷‚÷‚&+D&+D&+D&+D÷‚÷‚&+D&+D&+D&+D÷‚÷‚?&1?&1?&1?&1?&1?&1      ˆÿˆ   ˆÿˆ ˆÿˆ             ÿÿÿ     ÿÿÿ   ÿÿÿ                                                                                                                                                          ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1‹›´‹›´?&1?&1?&1?&1        ˆÿˆ   ˆÿˆ ˆÿˆ                ÿÿÿ   ÿÿÿÿÿÿÿÿÿ                   ÿÿ        ?&1?&1?&1?&1?&1?&1‹›´‹›´÷‚÷‚&+D&+D&+D&+D÷‚÷‚&+D&+D&+D&+D÷‚÷‚?&1?&1?&1?&1?&1?&1      ˆÿˆ   ˆÿˆ ˆÿˆ             ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  ÿÿÿÿÿÿÿÿÿ                                                                                                                                                           ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´?&1?&1?&1?&1                                                         ÿÿ        ?&1?&1?&1?&1?&1?&1?&1?&1÷‚÷‚÷‚÷‚ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ÷‚÷‚?&1?&1?&1?&1?&1?&1                                                                                                                                                                                                 ::U::U   ÿÿ     ?&1?&1?&1?&1‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´‹›´?&1?&1?&1?&1                                                         ÿÿ        ?&1?&1?&1?&1?&1?&1?&1?&1÷‚÷‚÷‚÷‚ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ÷‚÷‚?&1?&1?&1?&1?&1?&1                                                                                        ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ   ÿÿÿ ÿÿÿÿÿÿÿÿÿ                                                                        ::U::U   ÿÿ   ?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1                                                       ÿÿ      ?&1?&1?&1?&1?&1?&1?&1?&1›L£›L£÷‚÷‚‹›´‹›´÷‚÷‚÷‚÷‚÷‚÷‚‹›´‹›´›L£›L£?&1?&1?&1?&1?&1?&1                                                                                      ÿÿÿ  ÿÿÿ  ÿÿÿ     ÿÿÿ     ÿÿÿ     ÿÿÿÿÿÿ  ÿÿÿ ÿÿÿ  ÿÿÿ                                                                       ::U::U   ÿÿ   ?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1                                                       ÿÿ      ?&1?&1?&1?&1?&1?&1?&1?&1›L£›L£÷‚÷‚‹›´‹›´÷‚÷‚÷‚÷‚÷‚÷‚‹›´‹›´›L£›L£?&1?&1?&1?&1?&1?&1                                                                                      ÿÿÿ   ÿÿÿ ÿÿÿ     ÿÿÿ     ÿÿÿ     ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ   ÿÿÿ                                                                      ::U::U   ÿÿ ?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ‹›´‹›´ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ‹›´‹›´ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1                                                     ÿÿ      ?&1?&1?&1?&1÷‚÷‚÷‚÷‚›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ›L£›L£÷‚÷‚÷‚÷‚?&1?&1?&1?&1                                                                                    ÿÿÿ   ÿÿÿ ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿ   ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ   ÿÿÿ                                                                      ::U::U   ÿÿ ?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ‹›´‹›´ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ‹›´‹›´ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿˆªÿˆªÿˆªÿ           ÿÿÿÿÿÿÿÿÿ                         ÿÿ      ?&1?&1?&1?&1÷‚÷‚÷‚÷‚›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ›L£›L£÷‚÷‚÷‚÷‚?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿˆªÿˆªÿˆªÿ            ÿÿÿ    ÿÿÿÿÿÿÿÿÿ                                                  ÿÿÿ   ÿÿÿ ÿÿÿ     ÿÿÿ     ÿÿÿ     ÿÿÿ  ÿÿÿÿÿÿ ÿÿÿ   ÿÿÿ                                                                      ::U::U   ÿÿ ?&1?&1?&1?&1R`|R`|R`|R`|‹›´‹›´‹›´‹›´ÀËÜÀËÜR`|R`|R`|R`|ÀËÜÀËÜ‹›´‹›´‹›´‹›´R`|R`|R`|R`|?&1?&1?&1?&1    ˆªÿˆªÿ ˆªÿˆªÿ ˆªÿ   ˆªÿ         ÿÿÿ   ÿÿÿ                        ÿÿ      ?&1?&1?&1?&1÷‚÷‚÷‚÷‚›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ›L£›L£÷‚÷‚÷‚÷‚?&1?&1?&1?&1    ˆªÿˆªÿ ˆªÿˆªÿ ˆªÿ   ˆªÿ          ÿÿÿÿÿÿ   ÿÿÿ                                                     ÿÿÿ  ÿÿÿ  ÿÿÿ     ÿÿÿ     ÿÿÿ     ÿÿÿ   ÿÿÿ ÿÿÿ  ÿÿÿ                                                                       ::U::U   ÿÿ ?&1?&1?&1?&1R`|R`|R`|R`|‹›´‹›´‹›´‹›´ÀËÜÀËÜR`|R`|R`|R`|ÀËÜÀËÜ‹›´‹›´‹›´‹›´R`|R`|R`|R`|?&1?&1?&1?&1    ˆªÿ ˆªÿ ˆªÿ ˆªÿ   ˆªÿ         ÿÿÿ   ÿÿÿ                        ÿÿ      ?&1?&1?&1?&1÷‚÷‚÷‚÷‚›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ›L£›L£÷‚÷‚÷‚÷‚?&1?&1?&1?&1    ˆªÿ ˆªÿ ˆªÿ ˆªÿ   ˆªÿ           ÿÿÿ   ÿÿÿ                                                     ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ     ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ   ÿÿÿ ÿÿÿÿÿÿÿÿÿ                                                                        ::U::U   ÿÿ ?&1?&1?&1?&1R`|R`|R`|R`|?&1?&1½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ?&1?&1R`|R`|R`|R`|?&1?&1?&1?&1    ˆªÿ ˆªÿ ˆªÿ ˆªÿˆªÿˆªÿˆªÿ           ÿÿÿÿÿÿÿÿÿ                         ÿÿ      ?&1?&1?&1?&1›L£›L£›L£›L£?&1?&1½lJ½lJÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ?&1?&1›L£›L£›L£›L£?&1?&1?&1?&1    ˆªÿ ˆªÿ ˆªÿ ˆªÿˆªÿˆªÿˆªÿ            ÿÿÿ   ÿÿÿÿÿÿÿÿÿÿÿÿ                                                                                                                                                           ::U::U   ÿÿ ?&1?&1?&1?&1R`|R`|R`|R`|?&1?&1½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ½lJ?&1?&1R`|R`|R`|R`|?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿ             ÿÿÿ   ÿÿÿ                        ÿÿ      ?&1?&1?&1?&1›L£›L£›L£›L£?&1?&1½lJ½lJÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ?&1?&1›L£›L£›L£›L£?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿ               ÿÿÿ   ÿÿÿ   ÿÿÿ                                                                                                                                                          ::U::U   ÿÿ ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1R`|R`|R`|R`|?&1?&1?&1?&1R`|R`|R`|R`|?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿ             ÿÿÿ   ÿÿÿ                        ÿÿ      ?&1?&1?&1?&1›L£›L£›L£›L£?&1?&1›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËܪ·Ìª·Ì›L£›L£?&1?&1›L£›L£›L£›L£?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿ               ÿÿÿ   ÿÿÿ   ÿÿÿ                                                                                                                                                          ::U::U   ÿÿ ?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1R`|R`|R`|R`|?&1?&1?&1?&1R`|R`|R`|R`|?&1?&1?&1?&1?&1?&1?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿ              ÿÿÿÿÿÿÿÿÿ                         ÿÿ      ?&1?&1?&1?&1›L£›L£›L£›L£?&1?&1›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËܪ·Ìª·Ì›L£›L£?&1?&1›L£›L£›L£›L£?&1?&1?&1?&1    ˆªÿ   ˆªÿ ˆªÿ              ÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿ                                                                                                                                                           ::U::U   ÿÿ   ?&1?&1?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1?&1?&1                                                       ÿÿ        ?&1?&1?&1?&1?&1?&1›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                                       ÿÿÿÿÿÿÿÿÿ  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ   ÿÿÿ                   www   www    ÿÒJÿÒJÿÒJ                                                   ::U::U   ÿÿ   ?&1?&1?&1?&1?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1ÀËÜÀËÜÀËÜÀËÜ?&1?&1?&1?&1?&1?&1?&1?&1                                                       ÿÿ        ?&1?&1?&1?&1?&1?&1›L£›L£›L£›L£ÀËÜÀËÜÀËÜÀËÜÀËÜÀËÜ›L£›L£›L£›L£?&1?&1?&1?&1?&1?&1?&1?&1                                                                             ÿÿ          ÿÿÿ     ÿÿÿ   ÿÿÿ     ÿÿÿÿÿÿ ÿÿÿÿÿÿ                   www   www   ÿÒJ   ÿÒJ                                                  ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                  ÿÿ         ÿÿÿ     ÿÿÿ   ÿÿÿ     ÿÿÿ ÿÿÿ ÿÿÿ                    www www        ÿÒJ                                                  ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                   ÿÿ        ÿÿÿ     ÿÿÿ   ÿÿÿÿÿÿÿÿÿ   ÿÿÿ ÿÿÿ ÿÿÿ                     www       ÿÒJÿÒJ                                                   ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                  ÿÿ         ÿÿÿ     ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ                    www www     ÿÒJ                                                     ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                 ÿÿ          ÿÿÿ     ÿÿÿ   ÿÿÿ     ÿÿÿ   ÿÿÿ                   www   www   ÿÒJ                                                      ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                           ÿÿÿÿÿÿÿÿÿ    ÿÿÿ   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ   ÿÿÿ                   www   www   ÿÒJÿÒJÿÒJÿÒJÿÒJ                                                  ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                                                                                                                                   ::U::U   ÿÿ                                                                                      ÿÿ                                                                                                                                                                                                                                   ::U::U   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ                                                                                                                                                                                                                                   ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                     ÿÿÿÿÿÿÿÿÿÿÿÿ  ÿÿÿ   ÿÿÿ ÿÿÿ   ÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                     ÿÿÿ   ÿÿÿ ÿÿÿ   ÿÿÿ ÿÿÿÿÿÿ  ÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                     ÿÿÿ   ÿÿÿ ÿÿÿ   ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                     ÿÿÿÿÿÿÿÿÿÿÿÿ  ÿÿÿ   ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                     ÿÿÿ ÿÿÿ   ÿÿÿ   ÿÿÿ ÿÿÿ  ÿÿÿÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                     ÿÿÿ  ÿÿÿ  ÿÿÿ   ÿÿÿ ÿÿÿ   ÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                     ÿÿÿ   ÿÿÿ  ÿÿÿÿÿÿÿÿÿ  ÿÿÿ   ÿÿÿ                                                                                        ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U                                                                                                                                                                                                                                                                                                                              ::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U::U \ No newline at end of file diff --git a/selfhost/golden/menu.ppm b/selfhost/golden/menu.ppm new file mode 100644 index 00000000..4514adf2 --- /dev/null +++ b/selfhost/golden/menu.ppm @@ -0,0 +1,4 @@ +P6 +320 240 +255 +ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&IB2–…Fº¤NìÐ[ñÔ\¿¨P›‰GIB2&&&&&&&zm?ƒuAPH4&&&&&&&&&j^:ƒuA_U8&&&&~p?ƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuARJ5&&&&&&&&&&&HA2—†Fº¤NïÒ\ñÔ\ɱR¦“IcY9&&&&&&&&ƒuAƒuAf[:&&&&&&&&&dZ9ƒuA[R7&&&&&&&&HA2—†Fº¤NïÒ\ñÔ\ɱR¦“IcY9&&&&&&&&&&&&&&&~p?ƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuARJ5&&&&&&&TK5ƒuAvi>&&&&uh=ƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuA`V8&@:0ƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuA<7/&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&50-º¤NñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\«—K! (&&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ÔºU@;0&&&&&&&+(+´ŸMñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\Ò¹TJC2&&&&&&ñÔ\ñÔ\ðÓ\KD3&&&&&&&&³žMñÔ\ ŽH&&&&&&+(+´ŸMñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\Ò¹TJC2&&&&&&&&&&&&&æÊYñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ÔºU@;0&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\«—K&j^:ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\bX9&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&A<0ãÈYñÔ\ðÓ\ ŽH]S7LE3LE3cY9·¢NñÔ\ñÔ\ìQ'&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\º¤NƒuAƒuAƒuAƒuAƒuAƒuAƒuAÅ®QñÔ\ñÔ\ÞÃW*'+&&&&&62.ÛÁWñÔ\ñÔ\¸£Nj^:LE3LE3YP6�‹GíÐ[ñÔ\îÑ[dZ9&&&&&ñÔ\ñÔ\ñÔ\Õ¼U(&&&&&&&³žMñÔ\ ŽH&&&&&62.ÛÁWñÔ\ñÔ\¸£Nj^:LE3LE3YP6�‹GíÐ[ñÔ\îÑ[dZ9&&&&&&&&&&&&æÊYñÔ\º¤NƒuAƒuAƒuAƒuAƒuAƒuAƒuAÅ®QñÔ\ñÔ\ÞÃW*'+&&&&’�DñÔ\×½V&&&&ÔºUñÔ\ìQƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuA`V8&@:0ƒuAƒuAƒuAƒuAƒuAŸŒHñÔ\ñÔ\™ˆFƒuAƒuAƒuAƒuAƒuA<7/&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&$*ÜÁWñÔ\ÛÁWA<0&&&&&&yl>ñÔ\ñÔ\�€D&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&vi>ñÔ\ñÔ\ŠzB&&&& (ÔºUñÔ\åÉY[R7&&&&&&62.͵SñÔ\íÐ[G@2&&&&ñÔ\ñÔ\ñÔ\ñÔ\•„E&&&&&&&³žMñÔ\ ŽH&&&& (ÔºUñÔ\åÉY[R7&&&&&&62.͵SñÔ\íÐ[G@2&&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&vi>ñÔ\ñÔ\ŠzB&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&•„EñÔ\ìÐ[@:0&&&&&&&&­™KñÔ\ëÏ[)&*&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&&ʲSñÔ\ǯR&&&&Œ|CñÔ\îÑ[JC3&&&&&&&&+(+ÜÁWñÔ\ʲR&&&&ñÔ\ñÔ\Ó¹UñÔ\ñÔ\LE3&&&&&&³žMñÔ\ ŽH&&&&Œ|CñÔ\îÑ[JC3&&&&&&&&+(+ÜÁWñÔ\ʲR&&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&&ʲSñÔ\ǯR&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&! (éÍZñÔ\›‰G&&&&&&&&&A<0æÊY³žM;6/&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&&¥’IñÔ\Ù¿V&&& (æÊYñÔ\�‹G&&&&&&&&&&g\:ñÔ\ñÔ\UM5&&&ñÔ\ñÔ\g\:Ó¹UñÔ\Õ¼U(&&&&&³žMñÔ\ ŽH&&& (æÊYñÔ\�‹G&&&&&&&&&&g\:ñÔ\ñÔ\UM5&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&&¥’IñÔ\Ù¿V&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&^T7ñÔ\ñÔ\MF3&&&&&&&&&&&&&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&&ʲSñÔ\Å®Q&&&[R7ñÔ\ñÔ\JC2&&&&&&&&&&'äÉYñÔ\ŸŒH&&&ñÔ\ñÔ\_U8JC2ðÓ\ñÔ\•„E&&&&&³žMñÔ\ ŽH&&&[R7ñÔ\ñÔ\JC2&&&&&&&&&&'äÉYñÔ\ŸŒH&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&&ʲSñÔ\Å®Q&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&‹|CñÔ\îÑ['&&&&&&&&&&&&&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&yl>ñÔ\ñÔ\q@&&&Š{CñÔ\ëÏ['&&&&&&&&&&&­™KñÔ\зT&&&ñÔ\ñÔ\_U8&’�DñÔ\ñÔ\LE3&&&&³žMñÔ\ ŽH&&&Š{CñÔ\ëÏ['&&&&&&&&&&&­™KñÔ\зT&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&yl>ñÔ\ñÔ\q@&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&¥’IñÔ\Ö½U&&&&&&&&&&&&&&&&&ßÄXñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\¨”J&&&&æÊYñÔ\º¤NƒuAƒuAƒuAƒuAƒuAƒuAƒuA˳SñÔ\ñÔ\ʲR(&&&¨”JñÔ\Ó¹U&&&&&&&&&&&&Œ|CñÔ\ìÐ[&&&ñÔ\ñÔ\_U8&(Ó¹UñÔ\Õ¼U (&&&³žMñÔ\ ŽH&&&¨”JñÔ\Ó¹U&&&&&&&&&&&&Œ|CñÔ\ìÐ[&&&&&&&&&&æÊYñÔ\º¤NƒuAƒuAƒuAƒuAƒuAƒuAƒuA˳SñÔ\ñÔ\ʲR(&&&&’�DñÔ\×½V&&&&ÔºUñÔ\ÚÀVº¤Nº¤Nº¤Nº¤Nº¤Nº¤Nº¤Nº¤NJC2&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&­™KñÔ\Ì´S&&&&&&&&&&&&&&&&&ßÄXñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\¨”J&&&&æÊYñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\¢�I$")&&&&´ŸMñÔ\Å®Q&&&&&&&&&&&&€r@ñÔ\ñÔ\(&&ñÔ\ñÔ\_U8&&G@2ïÒ\ñÔ\™ˆF&&&³žMñÔ\ ŽH&&&´ŸMñÔ\Å®Q&&&&&&&&&&&&€r@ñÔ\ñÔ\(&&&&&&&&&æÊYñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\¢�I$")&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ñÔ\[R7&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&¦“IñÔ\ÔºU&&&&&&&&&&&&&&&&&ßÄXñÔ\¤‘ILE3LE3LE3LE3LE3LE3LE3LE3LE3ʲSñÔ\¨”J&&&&æÊYñÔ\Õ¼Uº¤Nº¤Nº¤NÀªPñÔ\ñÔ\éÌZyl>-*+&&&&&&²�LñÔ\ǯR&&&&&&&&&&&&„uAñÔ\ðÓ\'&&ñÔ\ñÔ\_U8&&&Ž~DñÔ\ñÔ\PH4&&³žMñÔ\ ŽH&&&²�LñÔ\ǯR&&&&&&&&&&&&„uAñÔ\ðÓ\'&&&&&&&&&æÊYñÔ\Õ¼Uº¤Nº¤Nº¤NÀªPñÔ\ñÔ\éÌZyl>-*+&&&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\ìQƒuAƒuAƒuAƒuAƒuAƒuAƒuAƒuA84.&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Ž~DñÔ\èÌZ&&&&&&&&&&&&&&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&50-ȰRñÔ\àÅXJC2&&&&&&œŠGñÔ\ÛÁW&&&&&&&&&&&&œŠGñÔ\ßÄX&&&ñÔ\ñÔ\_U8&&&'зTñÔ\×½V (&³žMñÔ\ ŽH&&&œŠGñÔ\ÛÁW&&&&&&&&&&&&œŠGñÔ\ßÄX&&&&&&&&&&æÊYñÔ\ƒuA&&&&50-ȰRñÔ\àÅXJC2&&&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&f[:ñÔ\ñÔ\73.&&&&&&&&&&dZ9E?1&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&'%*Ô»UñÔ\çËZ=8/&&&&&pd<ñÔ\ñÔ\-*+&&&&&&&&&&&ɱRñÔ\µ M&&&ñÔ\ñÔ\_U8&&&&G@2ïÒ\ñÔ\™ˆF&³žMñÔ\ ŽH&&&pd<ñÔ\ñÔ\-*+&&&&&&&&&&&ɱRñÔ\µ M&&&&&&&&&&æÊYñÔ\ƒuA&&&&&'%*Ô»UñÔ\çËZ=8/&&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+(+ïÒ\ñÔ\{m?&&&&&&&&& (èÌZñÔ\žŒG&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&D>1íÐ[ñÔ\Ò¹T(&&&&0,,ðÓ\ñÔ\yl>&&&&&&&&&&:5/ñÔ\ñÔ\ui=&&&ñÔ\ñÔ\_U8&&&&&Ž~DñÔ\ñÔ\PH4³žMñÔ\ ŽH&&&0,,ðÓ\ñÔ\yl>&&&&&&&&&&:5/ñÔ\ñÔ\ui=&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&D>1íÐ[ñÔ\Ò¹T(&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&³žMñÔ\Ù¿V(&&&&&&&&wj>ñÔ\ñÔ\QI4&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&‡xBñÔ\ñÔ\‘€D&&&&&¯›LñÔ\ßÄX(%*&&&&&&&&&±œLñÔ\èÌZ'%*&&&ñÔ\ñÔ\_U8&&&&&'зTñÔ\×½V¾§OñÔ\ ŽH&&&&¯›LñÔ\ßÄX(%*&&&&&&&&&±œLñÔ\èÌZ'%*&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&‡xBñÔ\ñÔ\‘€D&&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&HA2ñÔ\ñÔ\§“J&&&&&&&@:0èÌZñÔ\Å®Q&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&'ζSñÔ\ïÒ\C=1&&&&:5/êÎZñÔ\ÁªP"!)&&&&&&&Œ|CñÔ\ñÔ\q@&&&&ñÔ\ñÔ\_U8&&&&&&G@2ïÒ\ñÔ\ñÔ\ñÔ\ ŽH&&&&:5/êÎZñÔ\ÁªP"!)&&&&&&&Œ|CñÔ\ñÔ\q@&&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&'ζSñÔ\ïÒ\C=1&&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&�€DñÔ\ñÔ\ÁªPRJ5&&&(vi>æÊYñÔ\èÌZ=8/&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&IB2ñÔ\ñÔ\ʲR'&&&&g\:ñÔ\ñÔ\×½VdZ9&&&&G@2¶¡NñÔ\ñÔ\³žM&&&&&ñÔ\ñÔ\_U8&&&&&&&Ž~DñÔ\ñÔ\ñÔ\ ŽH&&&&&g\:ñÔ\ñÔ\×½VdZ9&&&&G@2¶¡NñÔ\ñÔ\³žM&&&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&IB2ñÔ\ñÔ\ʲR'&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&–…FñÔ\ñÔ\ñÔ\éÌZº¤NÀªPñÔ\ñÔ\ñÔ\âÇXMF3&&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&&™ˆFñÔ\ñÔ\q@&&&&&aW8åÉYñÔ\ñÔ\ñÔ\¿©Pº¤NåÉYñÔ\ñÔ\ñÔ\ŸŒH'&&&&&ñÔ\ñÔ\_U8&&&&&&&'зTñÔ\ñÔ\ ŽH&&&&&&aW8åÉYñÔ\ñÔ\ñÔ\¿©Pº¤NåÉYñÔ\ñÔ\ñÔ\ŸŒH'&&&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&&™ˆFñÔ\ñÔ\q@&&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&TK5·¢NñÔ\ñÔ\ñÔ\ñÔ\ñÔ\èÌZšˆF+(+&&&&&&ßÄXñÔ\Š{C&&&&&&&&&¾§OñÔ\¨”J&&&&æÊYñÔ\ƒuA&&&&&&&&&"!)ÛÁWñÔ\êÎZ51-&&&&&+)+•„EáÆXñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ª–JKD3&&&&&&&ñÔ\ñÔ\_U8&&&&&&&&G@2îÑ[ñÔ\ ŽH&&&&&&&+)+•„EáÆXñÔ\ñÔ\ñÔ\ñÔ\ñÔ\ª–JKD3&&&&&&&&&&&&&&æÊYñÔ\ƒuA&&&&&&&&&"!)ÛÁWñÔ\êÎZ51-&&’�DñÔ\×½V&&&&ÔºUñÔ\•„E&&&&&&&&&&&&&&&&&LE3ñÔ\ñÔ\A<0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'LE3LE3LE3IB2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&?90LE3LE3LE3&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&?90LE3LE3LE3&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Ž“¹AC[&&&&&&&&&&&&&&&&&&KNhuyš&0’—¾()<&&&&&&&&&&&&&&&&&&&&&&&&&68N56L&&&&&&&&&0’—¾()<&&&&&&&&&&&&&&&&&&&&&KNhuyš&&&&&&&ƒˆ¬ILe&&&&?AXŽ“¹&&jnŽbf„&&&&&&&&&&KNhuyš&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Ž“¹AC[&&&&&&&&&&&&&&&&&&KNhuyš&+TVr1&&&&&&&&&&&&&&&&&&&&&&&&&„§CE]&&&&&&&&&+TVr1&&&&&&&&&&&&&&&&&&&&&KNhuyš&&&&&&&ƒˆ¬ILe&&&&?AXŽ“¹&&jnŽbf„&&&&&&&&&&KNhuyš&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&,-AILeKNh*+>&&&&&&&Ž“¹AC[&&&&&)56L*&&#$6-.C&&&+,@MOi,-AKNhuyš&(56L+&&&&9EG`;&&%%8DF_>@W0&&-.B„‰­WZv()<&&,-AILeKNh*+>&&(56L+(56L&13HORl*+>&&&&%%8DF_>@W0&&&&+,@MOi,-AKNhuyš&&&&&&&ƒˆ¬ILe&&&&?AXŽ“¹&&jnŽbf„&&&&&&&+,@MOi,-AKNhuyš&&&%%8DF_>@W0&&(56L&:‘—½./D&*z¡uyš&0’—¾()<#$6�•»9:Q&&imŒae‚&&&& 2’—¾TVr&&#$7�”º68N&&QTo|�£&&„§CE]&"#5Š�µ&':&&Y\ytx™&0’—¾()<0’—¾UXt&&]`}sw˜&#$7�”º68N&&QTo|�£&)*>‘—½./D&*z¡uyš&&&&&&&ƒˆ¬ILe&&&&?AXŽ“¹&&jnŽbf„&&&&&)*>‘—½./D&*z¡uyš&#$7�”º68N&&QTo|�£&0’—¾SVq&&ƒˆ¬v{œ&&\`}jnŽ&+,@’—¾56L&&VYtƒˆ¬'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'56L@BZos“x}Ÿ&&&&&&Ž“¹AC[&&&&&""5’—¾$%7&&KNhuyš&KMg}�¤&&&NPkuyš&0’—¾()&&VYu’—¾lp�,uyšˆŽ³uyš~ƒ¦PSmŒ‘¶+0’—¾()<0’—¾()<&&GIb{€¢&&12G�†©�’¸Œ‘·„§)*>&&56L…Š®Š�´Œ‘¶ad‚uyš&&&&&&&&PSmŠ�µ’—¾’—¾�“¸TWr&&&jnŽbf„&&&&&&56L…Š®Š�´Œ‘¶ad‚uyš&&12G�†©�’¸Œ‘·„§)*>&0’—¾()<&&sw˜ORm&&MPjsw˜&&57Lƒˆ¬‰�´‘—½qu–#$6&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&0#$6&&&&&&&&&&&&&&&&&&&)*>&&&&&&&#$6&&&&&&&&&&%%8)&&&&&&&&&&&&&&!!3"#5&&&&&&&&&0#$6&&&&&&&&&&&&&&&&&&!!3"#5&&&&&&#$6&&&&&&&&&&&&&*+?,-A&&&&&&&&&&&&&&&#$6&&&&&&&!!3"#5&&&&&&&&&&&&&&&&&&$%7,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ­­²µµºˆˆˆˆˆ‹‹“»»À��•ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€€ˆ§§­»»ÀÔÔ×»»À©©¯€€‰ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝ÷÷ø¯¯´ˆˆˆˆ——ž÷÷ø››¢ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ••œææè÷÷øÜÜÞÙÙÜÛÛÝ÷÷øääæ��–ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝ÷÷øññò��•ˆˆˆ——ž÷÷ø››¢ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ�ììîááã��–ˆˆˆ‘‘™èèêÛÛ݈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝØØÛììí××Úˆˆˆ——ž÷÷ø››¢ˆˆˆ„„Œªª°»»À§§­€€‰ˆˆšš¡��–ˆˆˆœœ£��—ˆˆˆœœ£ŠŠ’ˆˆˆˆˆÂÂÆóóôŒŒ”ˆˆˆˆˆ¦¦¬ññò‹‹“ˆˆŒŒ”®®´»»À²²·ŽŽ–ˆˆˆ››¢ˆˆ�‘‘™ºº¿±±·‡‡�ˆ‘‘˜¹¹¾©©¯‚‚‹ˆˆˆ„„Œªª°»»À§§­€€‰ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒ¥¥«÷÷ø±±¶ˆˆ——ž÷÷ø››¢ˆˆ••�ëëíèèêÙÙÜééëääæ��•ˆÓÓÖÔÔ׈ˆ‘‘˜÷÷øÓÓÖˆˆ““š÷÷ø““›ˆˆˆˆˆëëìÏÏÒˆˆˆˆˆˆˆˆˆˆ««±õõöààâÙÙÜééëõõö¢¢¨ˆˆïïðÎÎÒððñÙÙÜððñååç±±·ììíÙÙÜôôõÞÞà€€ˆˆ••�ëëíèèêÙÙÜééëääæ��•ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆÍÍÐòòóŽŽ–ˆ——ž÷÷ø››¢ˆ€€‰ææèÖÖÙƒƒ‹ˆ††ŽÞÞáÕÕØˆ®®´òòó‚‚Šˆ±±¶ññòññò��‰ˆ¶¶»ææèˆˆˆˆˆˆˆ�÷÷ø··¼ˆˆˆˆˆˆˆˆˆƒƒŒððñ¿¿Äˆˆ��ŠããåÒÒÕˆˆïïðëë쉉‘ˆœœ£÷÷øãã円�ˆ¤¤«÷÷ø——ž€€‰ææèÖÖÙƒƒ‹ˆ††ŽÞÞáÕÕØˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆˆˆ�ììíÙÙ܈——ž÷÷ø››¢ˆ››¢÷÷ø››¢ˆˆˆ©©¯öö÷ˆˆ�ŠŠ’öö÷ŸŸ¥ˆÑÑÔÃÃÇöö÷™™ ˆÚÚÜÀÀňˆˆˆˆŽŽ–÷÷ø²²¸ˆˆˆ££©ÙÙÜÙÙÜÙÙÜÙÙܦ¦¬ˆ––�††Žˆˆƒƒ‹××ÚÚÚ݈ˆïïðÂÂLjˆ��Š÷÷ø··¼ˆˆŒŒ”÷÷ø  §››¢÷÷ø››¢ˆˆˆ©©¯öö÷ˆˆ�ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆˆ¥¥«÷÷ø±±¶——ž÷÷ø››¢ˆ¬¬²÷÷ø÷÷ø÷÷ø÷÷ø÷÷ø÷÷ø÷÷ø˜˜ŸˆÝÝß¿¿Ä��‰ññò››¢ááã¹¹¾‡‡�õõö››¢ˆˆˆˆˆ„„�öö÷¾¾Ãˆˆˆ——ž»»À»»À½½Á÷÷ø³³¸ˆŠŠ’½½ÁÙÙÜççé÷÷øóóôÛÛ݈ˆïïð¶¶»ˆˆˆ÷÷ø­­²ˆˆ‹‹“÷÷ø¡¡§¬¬²÷÷ø÷÷ø÷÷ø÷÷ø÷÷ø÷÷ø÷÷ø˜˜Ÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆˆˆÍÍÐòò󦦬÷÷ø››¢ˆªª°÷÷ø¥¥«��¤��¤��¤��¤��¤……Žˆ¸¸½ááã››¢ññò��‰ÁÁÅ××Ú©©¯ììˆˆˆˆˆˆˆÞÞááá㈈ˆˆˆˆƒƒ‹÷÷ø³³¸‡‡�êêìääæ»»À��¤‰‰‘ÎÎÑÛÛ݈ˆïï𵵺ˆˆˆ÷÷ø­­²ˆˆ‹‹“÷÷ø¡¡§ªª°÷÷ø¥¥«��¤��¤��¤��¤��¤……Žˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆˆˆˆˆ�ëëìêêë÷÷ø››¢ˆ••œ÷÷ø¦¦¬ˆˆˆ££ª¾¾ÂƒƒŒˆ““›öö÷ÄÄÈÓÓÖˆ¡¡§óóôÑÑÔÈÈ̈ˆˆˆˆˆˆ¨¨®÷÷ø··¼ˆˆˆˆˆ��•÷÷ø³³¸ªª°÷÷ø��—ˆˆˆààâÛÛÞˆˆïï𵵺ˆˆˆ÷÷ø­­²ˆˆ‹‹“÷÷ø¡¡§••œ÷÷ø¦¦¬ˆˆˆ££ª¾¾ÂƒƒŒˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆˆˆˆ££©÷÷ø÷÷ø››¢ˆˆ××Úêê윜£ˆ••œêêëÕÕØˆˆˆççéôôõ³³¹ˆ„„Œôôõ÷÷ø¢¢©ˆˆˆˆˆˆˆˆÈÈÌ÷÷øÒÒÕ¤¤ª��¤žž¤ÄÄÈððñððñ��¤žž¥÷÷ø¯¯µˆ„„Œ¾¾Ã÷÷øàà㈈ïï𵵺ˆˆˆ÷÷ø­­²ˆˆ‹‹“÷÷ø¡¡§ˆ××Úêê윜£ˆ••œêêëÕÕØˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÛÛÝÏÏÒˆˆˆˆˆËËÎ÷÷ø››¢ˆˆ‡‡�ÑÑÕ÷÷ø÷÷ø÷÷øÖÖÙ††ŽˆˆˆÂÂÆ÷÷ø••œˆˆÙÙÜññò‚‚‹ˆˆˆˆˆˆˆˆˆ©©¯ääæ÷÷ø÷÷ø÷÷øîîðÅÅÉŠŠ’ˆˆÃÃÇ÷÷ø÷÷ø÷÷øÉÉÍ··¼òòó„„�ˆïï𵵺ˆˆˆ÷÷ø­­²ˆˆ‹‹“÷÷ø¡¡§ˆ‡‡�ÑÑÕ÷÷ø÷÷ø÷÷øÖÖÙ††Žˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ……Ž��¤††�ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‡‡���¤’’™ˆˆˆˆˆˆ€€ˆ��¤ƒƒ‹ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ……Ž��¤††�ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:33Bxx‚’’š©©°ŠŠ’CCQ**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**://>**:**:‡‡�XXe**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:__kââäççéÀÀÅÀÀÅÞÞàîîïvv€**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:ww�­­³**:**:åå燇�**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:LLYëëí··¼55D**:**://>­­´ïïñRR_**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:²²¸¶¶»**:**:XXeAAO**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:µµ»ááã22A**:**:**:**:44Dããå„„�**:**:**:77Fxx‚ŽŽ–mmx--=**:**:**:XXe99HCCQ„„�……ŽBBP**:**:MM[ÂÂÇÅÅÉ\\h//?XXeAAO**:**:XXe99HCCQ„„�……ŽBBP**:**:**:ZZf>>M**:**:**:JJXOO\**:**:**:22Arr}ŽŽ–mmx,,<**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:00@íí£**:**:**:**:**:**:**:**:**:**:\\hääæÖÖÙÀÀÅààâÖÖÙHHU**:**:åå窪°èèêÀÀÅßßáîîï[[g**:••�ââäããåÀÀÅ;;Jåå燇�**:**:åå窪°èèêÀÀÅßßáîîï[[g**:**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:**:OO\ßßáÚÚÝÀÀÅÛÛÞÒÒÖBBP**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:HHVòòóyyƒ**:**:**:**:**:**:**:**:**:33Bááã´´º//?**:88GÎÎÒÉÉÍ**:**:ååçââäAAO**:33BÖÖÙ²²·**:**:²²¸¶¶»**:**:åå燇�**:**:ååçââäAAO**:33BÖÖÙ²²·**:**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:,,<ÖÖÙ»»À00@**:55DÉÉͺº¿**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:MM[òòóss}**:**:**:**:**:**:**:**:**:ggsòòóIIW**:**:**:jjuòòóHHU**:ååç››£**:**:**:¨¨®ÆÆÊ**:**:²²¸¶¶»**:**:åå燇�**:**:ååç››£**:**:**:¨¨®ÆÆÊ**:**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:YYfòòóXXe**:**:**:qq{ññò99H**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:99Hòòó‡‡�**:**:**:**:**:**:**:**:**:��‹ïïñ++;**:**:**:IIWòòó``l**:åå燇�**:**:**:¢¢©ÇÇË**:**:²²¸¶¶»**:**:åå燇�**:**:åå燇�**:**:**:¢¢©ÇÇË**:**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:uuòòóòòóòòóòòóòòóòòóòòóSS`**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:ÔÔ×¹¹¾**:**:**:**:**:**:½½Á§§­**:||†ññò//?**:**:**:PP]òòó\\i**:ååç„„�**:**:**:¢¢©ÇÇË**:**:²²¸¶¶»**:**:åå燇�**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:ëëíˆ**:**:**:±±·ÀÀÅ**:qq|òòóiit\\h\\h\\h\\h\\h44D**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:……Žòòó[[g**:**:**:**:XXeòòó��•**:XXeòòó^^j**:**:**:€€‰ððñ;;J**:ååç„„�**:**:**:¢¢©ÇÇË**:**:²²···¼**:**:åå燇�**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:çç銊“**:**:**:ÏÏÒÀÀÅ**:NN[òòókkw**:**:**:ffr““›11@**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:00@ÉÉÍêê놆�UUbQQ^��‹ååçÑÑÔ22A**:**:ÇÇËÖÖÙRR_**:ddpææè¨¨®**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:¨¨®ÕÕØ\\h00@åå燇�**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:ÃÃÈÖÖÙDDR33B��™ííîÀÀÅ**:**:½½ÁÝÝà[[g**:NN[ÜÜߺº¿**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:44D¡¡¨ììîòòóòòóòò󨨮99G**:**:**:99H··¼òòóòòóïïð��¤11@**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:ddpííîòòóZZfåå燇�**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:OO\ÛÛÞòòóòòó´´º––žÀÀÅ**:**:77F³³¹òòóòòóòòó»»À55D**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:SS`\\h--=**:**:**:**:**:**:**://?XXe**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:PP]77F**:**:**:**:**:**:**:44D\\h66E**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:44Cyyƒ——Ÿ­­´ŽŽ–JJX**:**:**:**:**:**:**:**:**:**:**:**:**:**://>**:**:‡‡�XXe**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:YYfààâïïðÀÀÅÀÀÅ××Úòò󣣪..=**:**:**:**:**:**:**:**:**:**:**:ww�­­³**:**:åå燇�**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:HHVééêÁÁÅ==K**:**:**:{{„ïïð  §**:**:**:**:**:**:**:**:**:**:**:²²¸¶¶»**:**:XXeAAO**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:±±·ààã44C**:**:**:**:**:‘‘™òòóKKX**:XXe::IPP]ŽŽ–vv�44D**:**:MM[ÂÂÇÅÅÉ\\h//?XXeAAO**:**:**:77Fxx‚ŽŽ–mmx--=**:**:**:XXe99HCCQ„„�……ŽBBP**:**:**:**:``lŽŽ–……ŽIIW**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**://?ëëí››£**:**:**:**:**:**:;;Jññò��•**:åå縸¾ããå¼¼Á××ÚààâIIW**:••�ââäããåÀÀÅ;;Jåå燇�**:**:\\hääæÖÖÙÀÀÅààâÖÖÙHHU**:**:åå窪°èèêÀÀÅßßáîîï[[g**:**:··¼ææèÀÀÅÇÇÌòòó‡‡�**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:JJXòòóyyƒ**:**:**:**:**:**:**:ÛÛݯ¯µ**:ååçââäCCQ**:22AÆÆÊÂÂÆ**:**:²²¸¶¶»**:**:åå燇�**:33Bááã´´º//?**:88GÎÎÒÉÉÍ**:**:ååçââäAAO**:33BÖÖÙ²²·**:RR_òòóNN[**:**:““›ààã**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:RR_òòónny**:**:**:**:**:**:**:ÓÓÖ··¼**:ååç��™**:**:**:llwòòó>>M**:²²¸¶¶»**:**:åå燇�**:ggsòòóIIW**:**:**:jjuòòóHHU**:ååç››£**:**:**:¨¨®ÆÆÊ**:GGUòò󣣪MMZ**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:BBPòò󀀊**:**:**:**:**:**:**:åå礤«**:ååçppz**:**:**:QQ^òòóWWd**:²²¸¶¶»**:**:åå燇�**:��‹ïïñ++;**:**:**:IIWòòó``l**:åå燇�**:**:**:¢¢©ÇÇË**:**:††�ììîòòóÝÝࣣªKKX**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:××Ú¸¸½**:**:**:**:**:**:WWcòòóuu**:ååçrr}**:**:**:WWdòòóRR_**:²²¸¶¶»**:**:åå燇�**:||†ññò//?**:**:**:PP]òòó\\i**:ååç„„�**:**:**:¢¢©ÇÇË**:**:**:33Bkkw¢¢©ááãééêCCQ**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:~~ˆòòóffr**:**:**:**:00@ÅÅÉÞÞà22A**:ååçžž¦**:**:**:……Žééê11@**:²²···¼**:**:åå燇�**:XXeòòó^^j**:**:**:€€‰ððñ;;J**:ååç„„�**:**:**:¢¢©ÇÇË**:UUb££ª,,<**:**:IIWòòónny**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:,,<´´ºîîï’’š[[gCCQjjuËËÏììî^^j**:**:ååçììînny**:aalææè””œ**:**:¨¨®ÕÕØ\\h00@åå燇�**:**:ÇÇËÖÖÙRR_**:ddpææè¨¨®**:**:ååç„„�**:**:**:¢¢©ÇÇË**:MMZññò””œ..=**:ŒŒ•ððñGGU**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:ŠŠ’ààâòòóòòóòòó¹¹¾NN[**:**:**:åå篯µààâòòóððñ››£--=**:**:ddpííîòòóZZfåå燇�**:**:99H··¼òòóòòóïïð��¤11@**:**:ååç„„�**:**:**:¢¢©ÇÇË**:**:xx‚ççéòòóòòóããåqq{**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:IIW\\h//?**:**:**:**:**:ååç„„�**:WWd--=**:**:**:**:**:**:**:**:**:**:**:**:**:**://?XXe**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:QQ^MM[**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:ååç„„�**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:ååç„„�**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:XXe@@N**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:55D{{„™™ °°¶‹‹”GGU**:**:**:**:**:**:**:**:**:**:**:**:**:‡‡�XXe**:**:**://>**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:eepååçêêëÀÀÅÀÀÅÛÛÞòòó™™ **:**:**:**:**:**:**:**:**:**:**:**:åå燇�**:**:ww�­­³**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:RR_ííî³³¹88G**:**:**:……Žòòó��™**:**:**:**:**:**:**:**:**:**:**:XXeAAO**:**:²²¸¶¶»**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:¿¿ÄÕÕØ//?**:**:**:**:**:žž¦îîï>>M**:ZZf>>M**:**:**:JJXOO\**:**:XXeAAO**:MM[ÂÂÇÅÅÉ\\h//?**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:::Iññò‰‰’**:**:**:**:**:**:KKXòòó}}‡**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:**:åå燇�**:••�ââäããåÀÀÅ;;J**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:\\iòòóeep**:**:**:**:**:**:**:êêìžž¦**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:**:åå燇�**:**:²²¸¶¶»**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:ccoòòó^^j**:**:**:**:**:**:**:ä俦¦­**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:**:åå燇�**:**:²²¸¶¶»**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:QQ^òòóqq|**:**:**:**:**:**:11@ððñ””œ**:ëëí}}‡**:**:**:¬¬²ÀÀÅ**:**:åå燇�**:**:²²¸¶¶»**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:--=åå稨®**:**:**://>**:**:ggsòòóeep**:ëëíˆ**:**:**:±±·ÀÀÅ**:**:åå燇�**:**:²²¸¶¶»**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:��˜ïïðWWd**:**:ªª°ËËÏaamÑÑÕÒÒÖ,,<**:çç銊“**:**:**:ÏÏÒÀÀÅ**:**:åå燇�**:**:²²···¼**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:00@ÂÂÇééꈈ‘WWdRR_ÃÃÈòòóòòóSS`**:**:ÃÃÈÖÖÙDDR33B��™ííîÀÀÅ**:**:åå燇�**:**:¨¨®ÕÕØ\\h00@**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**://?‘‘™ååçòòóòòóòòó±±·ÐÐÓÑÑÕggs**:OO\ÛÛÞòòóòòó´´º––žÀÀÅ**:**:åå燇�**:**:ddpííîòòóZZf**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:MMZ\\h**:**://?ˆˆ‘‰‰’**:**:**:PP]77F**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUw**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:UUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&UUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ZZ‚ \ No newline at end of file diff --git a/selfhost/golden/snake.ppm b/selfhost/golden/snake.ppm new file mode 100644 index 00000000..b8e73456 --- /dev/null +++ b/selfhost/golden/snake.ppm @@ -0,0 +1,4 @@ +P6 +320 240 +255 +****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................*******ÿÿÿÿÿÿÿÿÿ***ÿÿÿÿÿÿÿÿÿ...ÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ*************.....ÿà`ÿà`ÿà`........****************................****************................****************................****************................****************................****************................****************................****************................******ÿÿÿ***ÿÿÿ*ÿÿÿ***ÿÿÿ.ÿÿÿ...ÿÿÿ.ÿÿÿ...ÿÿÿ.ÿÿÿ.****************....ÿà`...ÿà`.......****************................****************................****************................****************................****************................****************................****************................****************................******ÿÿÿ*****ÿÿÿ***..ÿÿÿ...ÿÿÿ.ÿÿÿ...ÿÿÿ.ÿÿÿ.****************....ÿà`..ÿà`ÿà`.......****************................****************................****************................****************................****************................****************................****************................****************................*******ÿÿÿÿÿÿÿÿÿ**ÿÿÿ***..ÿÿÿ...ÿÿÿ.ÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿ***************....ÿà`.ÿà`.ÿà`.......****************................****************................****************................****************................****************................****************................****************................****************................**********ÿÿÿ*ÿÿÿ***..ÿÿÿ...ÿÿÿ.ÿÿÿ.ÿÿÿ...ÿÿÿ.****************....ÿà`ÿà`..ÿà`.......****************................****************................****************................****************................****************................****************................****************................****************................******ÿÿÿ***ÿÿÿ*ÿÿÿ***ÿÿÿ.ÿÿÿ...ÿÿÿ.ÿÿÿ..ÿÿÿ..ÿÿÿ.****************....ÿà`...ÿà`.......****************................****************................****************................****************................****************................****************................****************................****************................*******ÿÿÿÿÿÿÿÿÿ***ÿÿÿÿÿÿÿÿÿ...ÿÿÿÿÿÿÿÿÿ..ÿÿÿ...ÿÿÿ.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ*************.....ÿà`ÿà`ÿà`........****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************..ÿUUÿUUÿUUÿUUÿUUÿUU......ÿUUÿUUÿUUÿUUÿUUÿUU****ÿUUÿUU******ÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU..**************ÿUUÿUUÿUUÿUUÿUUÿUU....ÿUUÿUU......ÿUUÿUU**ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU**ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU........****************................****************................****************................****************................****************................****************................****************..ÿUUÿUUÿUUÿUUÿUUÿUU......ÿUUÿUUÿUUÿUUÿUUÿUU****ÿUUÿUU******ÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU..**************ÿUUÿUUÿUUÿUUÿUUÿUU....ÿUUÿUU......ÿUUÿUU**ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU**ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU........****************................****************................****************................****************................****************................****************................****************ÿUUÿUU......ÿUUÿUU..ÿUUÿUU..****ÿUUÿUU**ÿUUÿUUÿUUÿUU**ÿUUÿUUÿUUÿUU..ÿUUÿUU..........************ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUU**********ÿUUÿUU......ÿUUÿUU......****************................****************................****************................****************................****************................****************................****************ÿUUÿUU......ÿUUÿUU..ÿUUÿUU..****ÿUUÿUU**ÿUUÿUUÿUUÿUU**ÿUUÿUUÿUUÿUU..ÿUUÿUU..........************ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUU**********ÿUUÿUU......ÿUUÿUU......****************................****************................****************................****************................****************................****************................****************ÿUUÿUU..........ÿUUÿUU..****ÿUUÿUU**ÿUUÿUU**ÿUUÿUU**ÿUUÿUU..ÿUUÿUU..........************ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUU**********ÿUUÿUU......ÿUUÿUU......****************................****************................****************................****************................****************................****************................****************ÿUUÿUU..........ÿUUÿUU..****ÿUUÿUU**ÿUUÿUU**ÿUUÿUU**ÿUUÿUU..ÿUUÿUU..........************ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUU**********ÿUUÿUU......ÿUUÿUU......****************................****************................****************................****************................****************................****************................****************ÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU**ÿUUÿUU**ÿUUÿUU**ÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUU......************ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUUÿUUÿUUÿUUÿUU******ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU........****************................****************................****************................****************................****************................****************................****************ÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU**ÿUUÿUU**ÿUUÿUU**ÿUUÿUU..ÿUUÿUUÿUUÿUUÿUUÿUU......************ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUUÿUUÿUUÿUUÿUU******ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU........****************................****************................****************................................****************................****************................****************................ÿUUÿUU******ÿUUÿUU**ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU**ÿUUÿUU**********............ÿUUÿUU..****ÿUUÿUU**ÿUUÿUU******ÿUUÿUU..ÿUUÿUU..........ÿUUÿUU**ÿUUÿUU**********................****************................****************................****************................****************................****************................****************................ÿUUÿUU******ÿUUÿUU**ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU@À`@À`ÿUUÿUU@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`ÿUUÿUU@À`.****ÿUUÿUU**ÿUUÿUU******ÿUUÿUU..ÿUUÿUU..........ÿUUÿUU**ÿUUÿUU**********................****************................****************................****************................****************................****************................****************................ÿUUÿUU******ÿUUÿUU**ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU@À`@À`ÿUUÿUU@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`ÿUUÿUU@À`.****ÿUUÿUU****ÿUUÿUU**ÿUUÿUU....ÿUUÿUU..........ÿUUÿUU****ÿUUÿUU********................****************................****************................****************................****************................****************................****************................ÿUUÿUU******ÿUUÿUU**ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU@À`@À`ÿUUÿUU@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`ÿUUÿUU@À`.****ÿUUÿUU****ÿUUÿUU**ÿUUÿUU....ÿUUÿUU..........ÿUUÿUU****ÿUUÿUU********...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................**ÿUUÿUUÿUUÿUUÿUUÿUU****ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU@À`@À`ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`ÿUUÿUUÿUUÿUUÿUUÿUU********ÿUUÿUU**....ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU..ÿUUÿUU******ÿUUÿUU******...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................**ÿUUÿUUÿUUÿUUÿUUÿUU****ÿUUÿUU**....ÿUUÿUU..ÿUUÿUU......ÿUUÿUU@À`@À`ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`ÿUUÿUUÿUUÿUUÿUUÿUU********ÿUUÿUU**....ÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUU..ÿUUÿUU******ÿUUÿUU******...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************...à@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Zà@Z...****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************................****************................****************................****************................****************................****************................****************................****************................*@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`*.@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`@À`.****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************....ÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ**ÿÿÿÿÿÿÿÿÿ***ÿÿÿÿÿÿÿÿÿ.........ÿÿÿÿÿÿÿÿÿ..ÿÿÿ.**ÿÿÿ*ÿÿÿ***ÿÿÿ*******ÿÿÿ...ÿÿÿ.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ.ÿÿÿ...ÿÿÿ***************................****************................****************................****************................****************................****************................****************................****************....ÿÿÿ...ÿÿÿ.ÿÿÿ...ÿÿÿ.ÿÿÿ*****ÿÿÿ***ÿÿÿ*ÿÿÿ***ÿÿÿ.......ÿÿÿ...ÿÿÿ.ÿÿÿÿÿÿ**ÿÿÿ*ÿÿÿ***ÿÿÿ*******ÿÿÿ..ÿÿÿ..ÿÿÿ.....ÿÿÿ...ÿÿÿ***************................****************................****************................****************................****************................****************................****************................****************....ÿÿÿ...ÿÿÿ.ÿÿÿ...ÿÿÿ.ÿÿÿ*****ÿÿÿ*****ÿÿÿ***........ÿÿÿ...ÿÿÿ.ÿÿÿ.ÿÿÿ*ÿÿÿ**ÿÿÿ*ÿÿÿ********ÿÿÿ.ÿÿÿ...ÿÿÿ......ÿÿÿ.ÿÿÿ****************................****************................****************................****************................****************................****************................****************................****************....ÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿ****ÿÿÿÿÿÿÿÿÿ***ÿÿÿÿÿÿÿÿÿ........ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ.ÿÿÿ.ÿÿÿ*ÿÿÿ***ÿÿÿ*********ÿÿÿÿÿÿ....ÿÿÿÿÿÿÿÿÿ.....ÿÿÿ.****************................****************................****************................****************................****************................................****************................****************................****ÿÿÿ*****ÿÿÿ*ÿÿÿ***ÿÿÿ.........ÿÿÿ.....ÿÿÿ*******ÿÿÿ***ÿÿÿ*ÿÿÿ*.ÿÿÿÿÿÿ...ÿÿÿ.........ÿÿÿ*ÿÿÿ***ÿÿÿ*******ÿÿÿ*................****************................****************................****************................****************................****************................****************................****************................****ÿÿÿ*****ÿÿÿ**ÿÿÿ**ÿÿÿ.....ÿÿÿ...ÿÿÿ.ÿÿÿ...ÿÿÿ*******ÿÿÿ***ÿÿÿ*ÿÿÿ*..ÿÿÿ...ÿÿÿ.........ÿÿÿ**ÿÿÿ**ÿÿÿ*******ÿÿÿ*................****************................****************................****************................****************................****************................****************................****************................****ÿÿÿ*****ÿÿÿ***ÿÿÿ*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ..ÿÿÿÿÿÿÿÿÿ...ÿÿÿÿÿÿÿÿÿ********ÿÿÿ***ÿÿÿ*ÿÿÿ*..ÿÿÿ...ÿÿÿ.........ÿÿÿ***ÿÿÿ*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ***ÿÿÿ*................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................********************************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................****************................ \ No newline at end of file diff --git a/selfhost/io.ludic b/selfhost/io.ludic new file mode 100644 index 00000000..3ca2a035 --- /dev/null +++ b/selfhost/io.ludic @@ -0,0 +1,22 @@ +# io.ludic — reading the input file and writing the output, plus tiny stdio. +# The compiler reads one .ludic file whole and emits LLVM IR text to stdout. + +fn read_file(path: str) -> ptr { + let f = file_open(path, "rb") + if ptr_is_null(f) { return ptr_null() } + file_seek(f, 0, 2) + let n = file_tell(f) + file_seek(f, 0, 0) + let buf = mem_alloc(n + 1) + file_read(f, buf, n) + poke8(buf, n, 0) + file_close(f) + return buf +} + +# length of a NUL-terminated buffer +fn cstr_len(s: ptr) -> int { + let n = 0 + while peek8(s, n) != 0 { n = n + 1 } + return n +} diff --git a/selfhost/lex.ludic b/selfhost/lex.ludic new file mode 100644 index 00000000..6e798e55 --- /dev/null +++ b/selfhost/lex.ludic @@ -0,0 +1,138 @@ +# lex.ludic — source text -> a token slice. Mirrors compiler/front/lex.c. +# Tokens carry their kind, their text (identifiers, strings, operators), +# an integer value (numbers, char literals) and a line for diagnostics. + +const TK_ID: int = 0 +const TK_INT: int = 1 +const TK_STR: int = 2 +const TK_OP: int = 3 +const TK_NL: int = 4 +const TK_EOF: int = 5 +const TK_FLOAT: int = 6 + +struct Tok { kind: int = 0, text: ptr = ptr_null(), ival: int = 0, line: int = 0 } + +var toks: []Tok + +fn tok_push(kind: int, text: ptr, ival: int, line: int) -> void { + let t = new Tok + t.kind = kind t.text = text t.ival = ival t.line = line + push(toks, t) +} + +# does src match the 2-char operator op at position i? +fn two_at(src: ptr, i: int, a: int, b: int) -> bool { + return peek8(src, i) == a and peek8(src, i + 1) == b +} + +fn is_op1(c: int) -> bool { + # + - * / % < > = ( ) { } [ ] , : . ! @ + if c == 43 or c == 45 or c == 42 or c == 47 or c == 37 { return true } + if c == 60 or c == 62 or c == 61 { return true } + if c == 40 or c == 41 or c == 123 or c == 125 { return true } + if c == 91 or c == 93 or c == 44 or c == 58 or c == 46 { return true } + if c == 33 or c == 64 { return true } + return false +} + +fn lex(src: ptr) -> void { + toks = new []Tok + let i = 0 + let line = 1 + let n = slen(src) + while i < n { + let c = peek8(src, i) + if c == 10 { tok_push(TK_NL, ptr_null(), 0, line) line = line + 1 i = i + 1 continue } + if c == 32 or c == 9 or c == 13 { i = i + 1 continue } + if c == 35 { # '#' comment to end of line + while i < n and peek8(src, i) != 10 { i = i + 1 } + continue + } + if c == 34 { # "string" + i = i + 1 + let start = i + let out = mem_alloc(n) + let j = 0 + while i < n and peek8(src, i) != 34 { + if peek8(src, i) == 92 { # backslash escape + let e = peek8(src, i + 1) + let r = e + if e == 110 { r = 10 } + if e == 116 { r = 9 } + if e == 48 { r = 0 } + poke8(out, j, r) j = j + 1 i = i + 2 + } else { poke8(out, j, peek8(src, i)) j = j + 1 i = i + 1 } + } + i = i + 1 + poke8(out, j, 0) + tok_push(TK_STR, out, 0, line) + continue + } + if c == 39 { # 'c' char literal -> int + i = i + 1 + let v = 0 + if peek8(src, i) == 92 { + let e = peek8(src, i + 1) + if e == 110 { v = 10 } + if e == 116 { v = 9 } + if e == 48 { v = 0 } + i = i + 2 + } else { v = peek8(src, i) i = i + 1 } + if peek8(src, i) == 39 { i = i + 1 } + tok_push(TK_INT, ptr_null(), v, line) + continue + } + if char_is_digit(c) { + if c == 48 and peek8(src, i + 1) == 120 { # 0x hex + let v = 0 + i = i + 2 + while i < n { + let h = peek8(src, i) + let d = 0 + if char_is_digit(h) { d = h - 48 } + else { if h >= 97 and h <= 102 { d = h - 87 } + else { if h >= 65 and h <= 70 { d = h - 55 } else { break } } } + v = v * 16 + d + i = i + 1 + } + tok_push(TK_INT, ptr_null(), v, line) + continue + } + let v = 0 + while i < n and char_is_digit(peek8(src, i)) { v = v * 10 + (peek8(src, i) - 48) i = i + 1 } + # a fractional part makes it a Q16.16 fixed literal + if i < n and peek8(src, i) == 46 and char_is_digit(peek8(src, i + 1)) { + i = i + 1 + let fnum = 0 let fden = 1 + while i < n and char_is_digit(peek8(src, i)) { fnum = fnum * 10 + (peek8(src, i) - 48) fden = fden * 10 i = i + 1 } + let bits = shl(v, 16) + shl(fnum, 16) / fden + tok_push(TK_FLOAT, ptr_null(), bits, line) + continue + } + tok_push(TK_INT, ptr_null(), v, line) + continue + } + if char_is_alpha(c) { + let start = i + while i < n and char_is_alnum(peek8(src, i)) { i = i + 1 } + tok_push(TK_ID, substr(src, start, i - start), 0, line) + continue + } + if c == 59 { tok_push(TK_NL, ptr_null(), 0, line) i = i + 1 continue } # ';' + # two-character operators + if two_at(src, i, 45, 62) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # -> + if two_at(src, i, 61, 62) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # => + if two_at(src, i, 61, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # == + if two_at(src, i, 33, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # != + if two_at(src, i, 60, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # <= + if two_at(src, i, 62, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # >= + if two_at(src, i, 43, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # += + if two_at(src, i, 45, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # -= + if two_at(src, i, 42, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # *= + if two_at(src, i, 47, 61) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # /= + if two_at(src, i, 46, 46) { tok_push(TK_OP, substr(src, i, 2), 0, line) i = i + 2 continue } # .. + if is_op1(c) { tok_push(TK_OP, substr(src, i, 1), 0, line) i = i + 1 continue } + i = i + 1 # skip anything unrecognised + } + tok_push(TK_EOF, ptr_null(), 0, line) +} diff --git a/selfhost/ludicc.seed.ll b/selfhost/ludicc.seed.ll new file mode 100644 index 00000000..b4d759c4 --- /dev/null +++ b/selfhost/ludicc.seed.ll @@ -0,0 +1,19459 @@ +; Ludic (self-hosted) -> LLVM IR +declare i32 @printf(ptr, ...) +declare ptr @malloc(i64) +declare ptr @realloc(ptr, i64) +declare void @free(ptr) +declare ptr @fopen(ptr, ptr) +declare i64 @fread(ptr, i64, i64, ptr) +declare i64 @fwrite(ptr, i64, i64, ptr) +declare i32 @fseek(ptr, i64, i32) +declare i64 @ftell(ptr) +declare i32 @fclose(ptr) +declare void @exit(i32) +declare i32 @system(ptr) +declare ptr @getenv(ptr) +declare ptr @memcpy(ptr, ptr, i64) +declare ptr @memset(ptr, i32, i64) +declare i64 @strlen(ptr) +declare i32 @getchar() +declare i32 @putchar(i32) +declare i64 @time(ptr) +declare void @win_open(i32, i32, i32, ptr) +declare i32 @win_poll() +declare void @win_present(ptr, i32, i32) +declare i32 @win_running() +declare void @win_close() +@__stderrp = external global ptr +@.fmt_str = private unnamed_addr constant [3 x i8] c"%s\00" +@.fmt_int = private unnamed_addr constant [4 x i8] c"%d\0A\00" +@L_argc = internal global i32 0 +@L_argv = internal global ptr null +@.gametitle = private unnamed_addr constant [9 x i8] c"SelfHost\00" +%LSlice = type { ptr, i32, i32 } +%Str_Buf = type { ptr, i32, i32 } +%Str_Node = type { i32, ptr, i32, ptr, ptr, ptr, ptr, ptr, i32 } +%Str_Tok = type { i32, ptr, i32, i32 } +%Str_Val = type { ptr, ptr } +@g_toks = internal global ptr null +@g_pi = internal global i32 0 +@g_prog = internal global ptr null +@g_g_game_name = internal global ptr null +@g_loaded_paths = internal global ptr null +@g_cur_dir = internal global ptr null +@g_head = internal global ptr null +@g_code = internal global ptr null +@g_falloc = internal global ptr null +@g_ll_t = internal global i32 0 +@g_ll_lbl = internal global i32 0 +@g_ll_str = internal global i32 0 +@g_loc_name = internal global ptr null +@g_loc_reg = internal global ptr null +@g_loc_ty = internal global ptr null +@g_nloc = internal global i32 0 +@g_brk_lbl = internal global ptr null +@g_cnt_lbl = internal global ptr null +@g_nloop = internal global i32 0 +@g_ret_ty = internal global ptr null +@g_g_term = internal global i32 0 +@g_self_stk = internal global ptr null +@g_nself = internal global i32 0 +@g_mach_stk = internal global ptr null +@g_nmach = internal global i32 0 +@g_g_addr_ty = internal global ptr null +@g_g_intrin_ok = internal global i32 0 +@g_g_windowed = internal global i32 0 +@g_g_iok = internal global i32 0 +@g_uiw = internal global ptr null +@g_uiw_parent = internal global ptr null +@g_ui_roots = internal global ptr null +@.str0 = private unnamed_addr constant [3 x i8] c"rb\00" +@.str1 = private unnamed_addr constant [28 x i8] c"ludicc(self): parse error: \00" +@.str2 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str3 = private unnamed_addr constant [20 x i8] c"expected identifier\00" +@.str4 = private unnamed_addr constant [2 x i8] c"[\00" +@.str5 = private unnamed_addr constant [2 x i8] c"]\00" +@.str6 = private unnamed_addr constant [2 x i8] c"(\00" +@.str7 = private unnamed_addr constant [2 x i8] c")\00" +@.str8 = private unnamed_addr constant [2 x i8] c",\00" +@.str9 = private unnamed_addr constant [2 x i8] c")\00" +@.str10 = private unnamed_addr constant [5 x i8] c"true\00" +@.str11 = private unnamed_addr constant [6 x i8] c"false\00" +@.str12 = private unnamed_addr constant [4 x i8] c"new\00" +@.str13 = private unnamed_addr constant [2 x i8] c"(\00" +@.str14 = private unnamed_addr constant [2 x i8] c")\00" +@.str15 = private unnamed_addr constant [20 x i8] c"expected expression\00" +@.str16 = private unnamed_addr constant [2 x i8] c".\00" +@.str17 = private unnamed_addr constant [2 x i8] c"[\00" +@.str18 = private unnamed_addr constant [2 x i8] c"]\00" +@.str19 = private unnamed_addr constant [2 x i8] c"(\00" +@.str20 = private unnamed_addr constant [2 x i8] c"-\00" +@.str21 = private unnamed_addr constant [2 x i8] c"-\00" +@.str22 = private unnamed_addr constant [4 x i8] c"not\00" +@.str23 = private unnamed_addr constant [4 x i8] c"not\00" +@.str24 = private unnamed_addr constant [2 x i8] c"*\00" +@.str25 = private unnamed_addr constant [2 x i8] c"/\00" +@.str26 = private unnamed_addr constant [2 x i8] c"%\00" +@.str27 = private unnamed_addr constant [2 x i8] c"+\00" +@.str28 = private unnamed_addr constant [2 x i8] c"-\00" +@.str29 = private unnamed_addr constant [2 x i8] c"<\00" +@.str30 = private unnamed_addr constant [3 x i8] c"<=\00" +@.str31 = private unnamed_addr constant [2 x i8] c">\00" +@.str32 = private unnamed_addr constant [3 x i8] c">=\00" +@.str33 = private unnamed_addr constant [3 x i8] c"==\00" +@.str34 = private unnamed_addr constant [3 x i8] c"!=\00" +@.str35 = private unnamed_addr constant [4 x i8] c"and\00" +@.str36 = private unnamed_addr constant [4 x i8] c"and\00" +@.str37 = private unnamed_addr constant [3 x i8] c"or\00" +@.str38 = private unnamed_addr constant [3 x i8] c"or\00" +@.str39 = private unnamed_addr constant [2 x i8] c"{\00" +@.str40 = private unnamed_addr constant [2 x i8] c"}\00" +@.str41 = private unnamed_addr constant [2 x i8] c"=\00" +@.str42 = private unnamed_addr constant [2 x i8] c",\00" +@.str43 = private unnamed_addr constant [2 x i8] c"}\00" +@.str44 = private unnamed_addr constant [2 x i8] c"{\00" +@.str45 = private unnamed_addr constant [2 x i8] c"}\00" +@.str46 = private unnamed_addr constant [2 x i8] c"}\00" +@.str47 = private unnamed_addr constant [4 x i8] c"let\00" +@.str48 = private unnamed_addr constant [2 x i8] c":\00" +@.str49 = private unnamed_addr constant [2 x i8] c"=\00" +@.str50 = private unnamed_addr constant [7 x i8] c"return\00" +@.str51 = private unnamed_addr constant [2 x i8] c"}\00" +@.str52 = private unnamed_addr constant [3 x i8] c"if\00" +@.str53 = private unnamed_addr constant [5 x i8] c"else\00" +@.str54 = private unnamed_addr constant [3 x i8] c"if\00" +@.str55 = private unnamed_addr constant [5 x i8] c"when\00" +@.str56 = private unnamed_addr constant [6 x i8] c"while\00" +@.str57 = private unnamed_addr constant [4 x i8] c"for\00" +@.str58 = private unnamed_addr constant [2 x i8] c"(\00" +@.str59 = private unnamed_addr constant [3 x i8] c"..\00" +@.str60 = private unnamed_addr constant [6 x i8] c"spawn\00" +@.str61 = private unnamed_addr constant [8 x i8] c"machine\00" +@.str62 = private unnamed_addr constant [2 x i8] c"{\00" +@.str63 = private unnamed_addr constant [2 x i8] c"}\00" +@.str64 = private unnamed_addr constant [2 x i8] c"=\00" +@.str65 = private unnamed_addr constant [2 x i8] c"}\00" +@.str66 = private unnamed_addr constant [7 x i8] c"become\00" +@.str67 = private unnamed_addr constant [6 x i8] c"enter\00" +@.str68 = private unnamed_addr constant [8 x i8] c"despawn\00" +@.str69 = private unnamed_addr constant [6 x i8] c"break\00" +@.str70 = private unnamed_addr constant [9 x i8] c"continue\00" +@.str71 = private unnamed_addr constant [6 x i8] c"match\00" +@.str72 = private unnamed_addr constant [2 x i8] c"{\00" +@.str73 = private unnamed_addr constant [2 x i8] c"}\00" +@.str74 = private unnamed_addr constant [2 x i8] c",\00" +@.str75 = private unnamed_addr constant [3 x i8] c"=>\00" +@.str76 = private unnamed_addr constant [2 x i8] c"{\00" +@.str77 = private unnamed_addr constant [2 x i8] c"}\00" +@.str78 = private unnamed_addr constant [2 x i8] c"=\00" +@.str79 = private unnamed_addr constant [3 x i8] c"+=\00" +@.str80 = private unnamed_addr constant [3 x i8] c"-=\00" +@.str81 = private unnamed_addr constant [3 x i8] c"*=\00" +@.str82 = private unnamed_addr constant [3 x i8] c"/=\00" +@.str83 = private unnamed_addr constant [2 x i8] c"{\00" +@.str84 = private unnamed_addr constant [2 x i8] c"}\00" +@.str85 = private unnamed_addr constant [2 x i8] c":\00" +@.str86 = private unnamed_addr constant [2 x i8] c"=\00" +@.str87 = private unnamed_addr constant [2 x i8] c",\00" +@.str88 = private unnamed_addr constant [2 x i8] c"}\00" +@.str89 = private unnamed_addr constant [2 x i8] c":\00" +@.str90 = private unnamed_addr constant [2 x i8] c"=\00" +@.str91 = private unnamed_addr constant [2 x i8] c":\00" +@.str92 = private unnamed_addr constant [2 x i8] c"=\00" +@.str93 = private unnamed_addr constant [2 x i8] c"(\00" +@.str94 = private unnamed_addr constant [2 x i8] c")\00" +@.str95 = private unnamed_addr constant [2 x i8] c":\00" +@.str96 = private unnamed_addr constant [2 x i8] c",\00" +@.str97 = private unnamed_addr constant [2 x i8] c")\00" +@.str98 = private unnamed_addr constant [5 x i8] c"void\00" +@.str99 = private unnamed_addr constant [3 x i8] c"->\00" +@.str100 = private unnamed_addr constant [1 x i8] c"\00" +@.str101 = private unnamed_addr constant [7 x i8] c"import\00" +@.str102 = private unnamed_addr constant [29 x i8] c"expected \22path\22 after import\00" +@.str103 = private unnamed_addr constant [7 x i8] c"struct\00" +@.str104 = private unnamed_addr constant [10 x i8] c"component\00" +@.str105 = private unnamed_addr constant [10 x i8] c"archetype\00" +@.str106 = private unnamed_addr constant [7 x i8] c"system\00" +@.str107 = private unnamed_addr constant [5 x i8] c"edge\00" +@.str108 = private unnamed_addr constant [3 x i8] c"ui\00" +@.str109 = private unnamed_addr constant [4 x i8] c"var\00" +@.str110 = private unnamed_addr constant [6 x i8] c"const\00" +@.str111 = private unnamed_addr constant [7 x i8] c"export\00" +@.str112 = private unnamed_addr constant [3 x i8] c"fn\00" +@.str113 = private unnamed_addr constant [5 x i8] c"pure\00" +@.str114 = private unnamed_addr constant [5 x i8] c"pure\00" +@.str115 = private unnamed_addr constant [7 x i8] c"extern\00" +@.str116 = private unnamed_addr constant [5 x i8] c"main\00" +@.str117 = private unnamed_addr constant [21 x i8] c"expected declaration\00" +@.str118 = private unnamed_addr constant [20 x i8] c"cannot open import \00" +@.str119 = private unnamed_addr constant [1 x i8] c"\00" +@.str120 = private unnamed_addr constant [26 x i8] c"runtime/native/core.ludic\00" +@.str121 = private unnamed_addr constant [6 x i8] c"Ludic\00" +@.str122 = private unnamed_addr constant [7 x i8] c"import\00" +@.str123 = private unnamed_addr constant [5 x i8] c"game\00" +@.str124 = private unnamed_addr constant [7 x i8] c"module\00" +@.str125 = private unnamed_addr constant [2 x i8] c"{\00" +@.str126 = private unnamed_addr constant [2 x i8] c"}\00" +@.str127 = private unnamed_addr constant [2 x i8] c"{\00" +@.str128 = private unnamed_addr constant [2 x i8] c"}\00" +@.str129 = private unnamed_addr constant [2 x i8] c":\00" +@.str130 = private unnamed_addr constant [2 x i8] c"=\00" +@.str131 = private unnamed_addr constant [2 x i8] c",\00" +@.str132 = private unnamed_addr constant [2 x i8] c"}\00" +@.str133 = private unnamed_addr constant [2 x i8] c"[\00" +@.str134 = private unnamed_addr constant [2 x i8] c"[\00" +@.str135 = private unnamed_addr constant [2 x i8] c"]\00" +@.str136 = private unnamed_addr constant [5 x i8] c"edge\00" +@.str137 = private unnamed_addr constant [7 x i8] c"Update\00" +@.str138 = private unnamed_addr constant [2 x i8] c"@\00" +@.str139 = private unnamed_addr constant [2 x i8] c"(\00" +@.str140 = private unnamed_addr constant [2 x i8] c"(\00" +@.str141 = private unnamed_addr constant [2 x i8] c")\00" +@.str142 = private unnamed_addr constant [6 x i8] c"phase\00" +@.str143 = private unnamed_addr constant [6 x i8] c"reads\00" +@.str144 = private unnamed_addr constant [7 x i8] c"writes\00" +@.str145 = private unnamed_addr constant [6 x i8] c"needs\00" +@.str146 = private unnamed_addr constant [5 x i8] c"uses\00" +@.str147 = private unnamed_addr constant [6 x i8] c"query\00" +@.str148 = private unnamed_addr constant [2 x i8] c"(\00" +@.str149 = private unnamed_addr constant [2 x i8] c"(\00" +@.str150 = private unnamed_addr constant [2 x i8] c")\00" +@.str151 = private unnamed_addr constant [2 x i8] c",\00" +@.str152 = private unnamed_addr constant [2 x i8] c")\00" +@.str153 = private unnamed_addr constant [2 x i8] c"[\00" +@.str154 = private unnamed_addr constant [2 x i8] c"]\00" +@.str155 = private unnamed_addr constant [2 x i8] c"{\00" +@.str156 = private unnamed_addr constant [2 x i8] c"}\00" +@.str157 = private unnamed_addr constant [2 x i8] c",\00" +@.str158 = private unnamed_addr constant [2 x i8] c"]\00" +@.str159 = private unnamed_addr constant [6 x i8] c"where\00" +@.str160 = private unnamed_addr constant [2 x i8] c"(\00" +@.str161 = private unnamed_addr constant [2 x i8] c")\00" +@.str162 = private unnamed_addr constant [2 x i8] c",\00" +@.str163 = private unnamed_addr constant [2 x i8] c")\00" +@.str164 = private unnamed_addr constant [2 x i8] c"{\00" +@.str165 = private unnamed_addr constant [2 x i8] c"}\00" +@.str166 = private unnamed_addr constant [2 x i8] c"=\00" +@.str167 = private unnamed_addr constant [2 x i8] c",\00" +@.str168 = private unnamed_addr constant [2 x i8] c"}\00" +@.str169 = private unnamed_addr constant [2 x i8] c"{\00" +@.str170 = private unnamed_addr constant [2 x i8] c"}\00" +@.str171 = private unnamed_addr constant [2 x i8] c",\00" +@.str172 = private unnamed_addr constant [2 x i8] c"}\00" +@.str173 = private unnamed_addr constant [2 x i8] c"(\00" +@.str174 = private unnamed_addr constant [2 x i8] c")\00" +@.str175 = private unnamed_addr constant [2 x i8] c":\00" +@.str176 = private unnamed_addr constant [2 x i8] c",\00" +@.str177 = private unnamed_addr constant [2 x i8] c")\00" +@.str178 = private unnamed_addr constant [5 x i8] c"void\00" +@.str179 = private unnamed_addr constant [3 x i8] c"->\00" +@.str180 = private unnamed_addr constant [2 x i8] c"=\00" +@.str181 = private unnamed_addr constant [2 x i8] c"=\00" +@.str182 = private unnamed_addr constant [2 x i8] c"=\00" +@.str183 = private unnamed_addr constant [2 x i8] c"{\00" +@.str184 = private unnamed_addr constant [2 x i8] c"}\00" +@.str185 = private unnamed_addr constant [2 x i8] c"}\00" +@.str186 = private unnamed_addr constant [2 x i8] c"{\00" +@.str187 = private unnamed_addr constant [2 x i8] c"}\00" +@.str188 = private unnamed_addr constant [3 x i8] c"%t\00" +@.str189 = private unnamed_addr constant [3 x i8] c" \00" +@.str190 = private unnamed_addr constant [11 x i8] c" = alloca \00" +@.str191 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str192 = private unnamed_addr constant [3 x i8] c"%t\00" +@.str193 = private unnamed_addr constant [4 x i8] c"int\00" +@.str194 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str195 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str196 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str197 = private unnamed_addr constant [5 x i8] c"void\00" +@.str198 = private unnamed_addr constant [5 x i8] c"void\00" +@.str199 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str200 = private unnamed_addr constant [6 x i8] c"%Str_\00" +@.str201 = private unnamed_addr constant [6 x i8] c"%Cmp_\00" +@.str202 = private unnamed_addr constant [4 x i8] c"int\00" +@.str203 = private unnamed_addr constant [6 x i8] c"@.str\00" +@.str204 = private unnamed_addr constant [35 x i8] c" = private unnamed_addr constant [\00" +@.str205 = private unnamed_addr constant [10 x i8] c" x i8] c\22\00" +@.str206 = private unnamed_addr constant [6 x i8] c"\5C00\22\0A\00" +@.str207 = private unnamed_addr constant [3 x i8] c" \00" +@.str208 = private unnamed_addr constant [35 x i8] c" = getelementptr inbounds i8, ptr \00" +@.str209 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str210 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str211 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str212 = private unnamed_addr constant [5 x i8] c"null\00" +@.str213 = private unnamed_addr constant [2 x i8] c"0\00" +@.str214 = private unnamed_addr constant [2 x i8] c"-\00" +@.str215 = private unnamed_addr constant [2 x i8] c"-\00" +@.str216 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str217 = private unnamed_addr constant [5 x i8] c"null\00" +@.str218 = private unnamed_addr constant [2 x i8] c"0\00" +@.str219 = private unnamed_addr constant [34 x i8] c"; Ludic (self-hosted) -> LLVM IR\0A\00" +@.str220 = private unnamed_addr constant [31 x i8] c"declare i32 @printf(ptr, ...)\0A\00" +@.str221 = private unnamed_addr constant [26 x i8] c"declare ptr @malloc(i64)\0A\00" +@.str222 = private unnamed_addr constant [32 x i8] c"declare ptr @realloc(ptr, i64)\0A\00" +@.str223 = private unnamed_addr constant [25 x i8] c"declare void @free(ptr)\0A\00" +@.str224 = private unnamed_addr constant [30 x i8] c"declare ptr @fopen(ptr, ptr)\0A\00" +@.str225 = private unnamed_addr constant [40 x i8] c"declare i64 @fread(ptr, i64, i64, ptr)\0A\00" +@.str226 = private unnamed_addr constant [41 x i8] c"declare i64 @fwrite(ptr, i64, i64, ptr)\0A\00" +@.str227 = private unnamed_addr constant [35 x i8] c"declare i32 @fseek(ptr, i64, i32)\0A\00" +@.str228 = private unnamed_addr constant [25 x i8] c"declare i64 @ftell(ptr)\0A\00" +@.str229 = private unnamed_addr constant [26 x i8] c"declare i32 @fclose(ptr)\0A\00" +@.str230 = private unnamed_addr constant [25 x i8] c"declare void @exit(i32)\0A\00" +@.str231 = private unnamed_addr constant [26 x i8] c"declare i32 @system(ptr)\0A\00" +@.str232 = private unnamed_addr constant [26 x i8] c"declare ptr @getenv(ptr)\0A\00" +@.str233 = private unnamed_addr constant [36 x i8] c"declare ptr @memcpy(ptr, ptr, i64)\0A\00" +@.str234 = private unnamed_addr constant [36 x i8] c"declare ptr @memset(ptr, i32, i64)\0A\00" +@.str235 = private unnamed_addr constant [26 x i8] c"declare i64 @strlen(ptr)\0A\00" +@.str236 = private unnamed_addr constant [24 x i8] c"declare i32 @getchar()\0A\00" +@.str237 = private unnamed_addr constant [27 x i8] c"declare i32 @putchar(i32)\0A\00" +@.str238 = private unnamed_addr constant [24 x i8] c"declare i64 @time(ptr)\0A\00" +@.str239 = private unnamed_addr constant [44 x i8] c"declare void @win_open(i32, i32, i32, ptr)\0A\00" +@.str240 = private unnamed_addr constant [25 x i8] c"declare i32 @win_poll()\0A\00" +@.str241 = private unnamed_addr constant [42 x i8] c"declare void @win_present(ptr, i32, i32)\0A\00" +@.str242 = private unnamed_addr constant [28 x i8] c"declare i32 @win_running()\0A\00" +@.str243 = private unnamed_addr constant [27 x i8] c"declare void @win_close()\0A\00" +@.str244 = private unnamed_addr constant [34 x i8] c"@__stderrp = external global ptr\0A\00" +@.str245 = private unnamed_addr constant [61 x i8] c"@.fmt_str = private unnamed_addr constant [3 x i8] c\22%s\5C00\22\0A\00" +@.str246 = private unnamed_addr constant [64 x i8] c"@.fmt_int = private unnamed_addr constant [4 x i8] c\22%d\5C0A\5C00\22\0A\00" +@.str247 = private unnamed_addr constant [33 x i8] c"@L_argc = internal global i32 0\0A\00" +@.str248 = private unnamed_addr constant [36 x i8] c"@L_argv = internal global ptr null\0A\00" +@.str249 = private unnamed_addr constant [46 x i8] c"@.gametitle = private unnamed_addr constant [\00" +@.str250 = private unnamed_addr constant [10 x i8] c" x i8] c\22\00" +@.str251 = private unnamed_addr constant [6 x i8] c"\5C00\22\0A\00" +@.str252 = private unnamed_addr constant [34 x i8] c"%LSlice = type { ptr, i32, i32 }\0A\00" +@.str253 = private unnamed_addr constant [6 x i8] c"%Str_\00" +@.str254 = private unnamed_addr constant [11 x i8] c" = type { \00" +@.str255 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str256 = private unnamed_addr constant [3 x i8] c", \00" +@.str257 = private unnamed_addr constant [4 x i8] c" }\0A\00" +@.str258 = private unnamed_addr constant [4 x i8] c"@g_\00" +@.str259 = private unnamed_addr constant [20 x i8] c" = internal global \00" +@.str260 = private unnamed_addr constant [2 x i8] c" \00" +@.str261 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str262 = private unnamed_addr constant [32 x i8] c"member access on non-aggregate \00" +@.str263 = private unnamed_addr constant [15 x i8] c"no such field \00" +@.str264 = private unnamed_addr constant [3 x i8] c" \00" +@.str265 = private unnamed_addr constant [27 x i8] c" = getelementptr inbounds \00" +@.str266 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str267 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str268 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str269 = private unnamed_addr constant [21 x i8] c"indexing a non-slice\00" +@.str270 = private unnamed_addr constant [3 x i8] c" \00" +@.str271 = private unnamed_addr constant [40 x i8] c" = getelementptr inbounds %LSlice, ptr \00" +@.str272 = private unnamed_addr constant [16 x i8] c", i32 0, i32 0\0A\00" +@.str273 = private unnamed_addr constant [3 x i8] c" \00" +@.str274 = private unnamed_addr constant [18 x i8] c" = load ptr, ptr \00" +@.str275 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str276 = private unnamed_addr constant [3 x i8] c" \00" +@.str277 = private unnamed_addr constant [27 x i8] c" = getelementptr inbounds \00" +@.str278 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str279 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str280 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str281 = private unnamed_addr constant [9 x i8] c"ptr_null\00" +@.str282 = private unnamed_addr constant [10 x i8] c"mem_alloc\00" +@.str283 = private unnamed_addr constant [12 x i8] c"mem_realloc\00" +@.str284 = private unnamed_addr constant [6 x i8] c"peek8\00" +@.str285 = private unnamed_addr constant [6 x i8] c"poke8\00" +@.str286 = private unnamed_addr constant [12 x i8] c"ptr_is_null\00" +@.str287 = private unnamed_addr constant [10 x i8] c"file_open\00" +@.str288 = private unnamed_addr constant [10 x i8] c"file_read\00" +@.str289 = private unnamed_addr constant [11 x i8] c"file_write\00" +@.str290 = private unnamed_addr constant [10 x i8] c"file_seek\00" +@.str291 = private unnamed_addr constant [10 x i8] c"file_tell\00" +@.str292 = private unnamed_addr constant [11 x i8] c"file_close\00" +@.str293 = private unnamed_addr constant [10 x i8] c"print_str\00" +@.str294 = private unnamed_addr constant [10 x i8] c"print_int\00" +@.str295 = private unnamed_addr constant [8 x i8] c"os_argc\00" +@.str296 = private unnamed_addr constant [7 x i8] c"os_arg\00" +@.str297 = private unnamed_addr constant [8 x i8] c"os_exit\00" +@.str298 = private unnamed_addr constant [12 x i8] c"file_stderr\00" +@.str299 = private unnamed_addr constant [10 x i8] c"os_system\00" +@.str300 = private unnamed_addr constant [10 x i8] c"os_getenv\00" +@.str301 = private unnamed_addr constant [4 x i8] c"shl\00" +@.str302 = private unnamed_addr constant [4 x i8] c"shr\00" +@.str303 = private unnamed_addr constant [5 x i8] c"band\00" +@.str304 = private unnamed_addr constant [4 x i8] c"bor\00" +@.str305 = private unnamed_addr constant [5 x i8] c"bxor\00" +@.str306 = private unnamed_addr constant [5 x i8] c"bnot\00" +@.str307 = private unnamed_addr constant [7 x i8] c"peek32\00" +@.str308 = private unnamed_addr constant [7 x i8] c"poke32\00" +@.str309 = private unnamed_addr constant [3 x i8] c" \00" +@.str310 = private unnamed_addr constant [4 x i8] c" = \00" +@.str311 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str312 = private unnamed_addr constant [9 x i8] c"ptr_null\00" +@.str313 = private unnamed_addr constant [5 x i8] c"null\00" +@.str314 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str315 = private unnamed_addr constant [10 x i8] c"mem_alloc\00" +@.str316 = private unnamed_addr constant [10 x i8] c"zext i32 \00" +@.str317 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str318 = private unnamed_addr constant [22 x i8] c"call ptr @malloc(i64 \00" +@.str319 = private unnamed_addr constant [2 x i8] c")\00" +@.str320 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str321 = private unnamed_addr constant [12 x i8] c"mem_realloc\00" +@.str322 = private unnamed_addr constant [10 x i8] c"zext i32 \00" +@.str323 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str324 = private unnamed_addr constant [23 x i8] c"call ptr @realloc(ptr \00" +@.str325 = private unnamed_addr constant [7 x i8] c", i64 \00" +@.str326 = private unnamed_addr constant [2 x i8] c")\00" +@.str327 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str328 = private unnamed_addr constant [6 x i8] c"peek8\00" +@.str329 = private unnamed_addr constant [14 x i8] c"load i8, ptr \00" +@.str330 = private unnamed_addr constant [9 x i8] c"zext i8 \00" +@.str331 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str332 = private unnamed_addr constant [4 x i8] c"int\00" +@.str333 = private unnamed_addr constant [6 x i8] c"poke8\00" +@.str334 = private unnamed_addr constant [11 x i8] c"trunc i32 \00" +@.str335 = private unnamed_addr constant [7 x i8] c" to i8\00" +@.str336 = private unnamed_addr constant [12 x i8] c" store i8 \00" +@.str337 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str338 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str339 = private unnamed_addr constant [2 x i8] c"0\00" +@.str340 = private unnamed_addr constant [5 x i8] c"void\00" +@.str341 = private unnamed_addr constant [12 x i8] c"ptr_is_null\00" +@.str342 = private unnamed_addr constant [13 x i8] c"icmp eq ptr \00" +@.str343 = private unnamed_addr constant [7 x i8] c", null\00" +@.str344 = private unnamed_addr constant [9 x i8] c"zext i1 \00" +@.str345 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str346 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str347 = private unnamed_addr constant [10 x i8] c"file_open\00" +@.str348 = private unnamed_addr constant [21 x i8] c"call ptr @fopen(ptr \00" +@.str349 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str350 = private unnamed_addr constant [2 x i8] c")\00" +@.str351 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str352 = private unnamed_addr constant [10 x i8] c"file_read\00" +@.str353 = private unnamed_addr constant [11 x i8] c"file_write\00" +@.str354 = private unnamed_addr constant [10 x i8] c"zext i32 \00" +@.str355 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str356 = private unnamed_addr constant [7 x i8] c"@fread\00" +@.str357 = private unnamed_addr constant [11 x i8] c"file_write\00" +@.str358 = private unnamed_addr constant [8 x i8] c"@fwrite\00" +@.str359 = private unnamed_addr constant [10 x i8] c"call i64 \00" +@.str360 = private unnamed_addr constant [6 x i8] c"(ptr \00" +@.str361 = private unnamed_addr constant [14 x i8] c", i64 1, i64 \00" +@.str362 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str363 = private unnamed_addr constant [2 x i8] c")\00" +@.str364 = private unnamed_addr constant [11 x i8] c"trunc i64 \00" +@.str365 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str366 = private unnamed_addr constant [4 x i8] c"int\00" +@.str367 = private unnamed_addr constant [10 x i8] c"file_seek\00" +@.str368 = private unnamed_addr constant [10 x i8] c"sext i32 \00" +@.str369 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str370 = private unnamed_addr constant [21 x i8] c"call i32 @fseek(ptr \00" +@.str371 = private unnamed_addr constant [7 x i8] c", i64 \00" +@.str372 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str373 = private unnamed_addr constant [2 x i8] c")\00" +@.str374 = private unnamed_addr constant [4 x i8] c"int\00" +@.str375 = private unnamed_addr constant [10 x i8] c"file_tell\00" +@.str376 = private unnamed_addr constant [21 x i8] c"call i64 @ftell(ptr \00" +@.str377 = private unnamed_addr constant [2 x i8] c")\00" +@.str378 = private unnamed_addr constant [11 x i8] c"trunc i64 \00" +@.str379 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str380 = private unnamed_addr constant [4 x i8] c"int\00" +@.str381 = private unnamed_addr constant [11 x i8] c"file_close\00" +@.str382 = private unnamed_addr constant [24 x i8] c" call i32 @fclose(ptr \00" +@.str383 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str384 = private unnamed_addr constant [2 x i8] c"0\00" +@.str385 = private unnamed_addr constant [5 x i8] c"void\00" +@.str386 = private unnamed_addr constant [10 x i8] c"print_str\00" +@.str387 = private unnamed_addr constant [50 x i8] c" call i32 (ptr, ...) @printf(ptr @.fmt_str, ptr \00" +@.str388 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str389 = private unnamed_addr constant [2 x i8] c"0\00" +@.str390 = private unnamed_addr constant [5 x i8] c"void\00" +@.str391 = private unnamed_addr constant [10 x i8] c"print_int\00" +@.str392 = private unnamed_addr constant [50 x i8] c" call i32 (ptr, ...) @printf(ptr @.fmt_int, i32 \00" +@.str393 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str394 = private unnamed_addr constant [2 x i8] c"0\00" +@.str395 = private unnamed_addr constant [5 x i8] c"void\00" +@.str396 = private unnamed_addr constant [8 x i8] c"os_argc\00" +@.str397 = private unnamed_addr constant [22 x i8] c"load i32, ptr @L_argc\00" +@.str398 = private unnamed_addr constant [4 x i8] c"int\00" +@.str399 = private unnamed_addr constant [7 x i8] c"os_arg\00" +@.str400 = private unnamed_addr constant [22 x i8] c"load ptr, ptr @L_argv\00" +@.str401 = private unnamed_addr constant [24 x i8] c"getelementptr ptr, ptr \00" +@.str402 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str403 = private unnamed_addr constant [15 x i8] c"load ptr, ptr \00" +@.str404 = private unnamed_addr constant [4 x i8] c"str\00" +@.str405 = private unnamed_addr constant [8 x i8] c"os_exit\00" +@.str406 = private unnamed_addr constant [23 x i8] c" call void @exit(i32 \00" +@.str407 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str408 = private unnamed_addr constant [15 x i8] c" unreachable\0A\00" +@.str409 = private unnamed_addr constant [2 x i8] c"0\00" +@.str410 = private unnamed_addr constant [5 x i8] c"void\00" +@.str411 = private unnamed_addr constant [12 x i8] c"file_stderr\00" +@.str412 = private unnamed_addr constant [25 x i8] c"load ptr, ptr @__stderrp\00" +@.str413 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str414 = private unnamed_addr constant [10 x i8] c"os_system\00" +@.str415 = private unnamed_addr constant [22 x i8] c"call i32 @system(ptr \00" +@.str416 = private unnamed_addr constant [2 x i8] c")\00" +@.str417 = private unnamed_addr constant [4 x i8] c"int\00" +@.str418 = private unnamed_addr constant [10 x i8] c"os_getenv\00" +@.str419 = private unnamed_addr constant [22 x i8] c"call ptr @getenv(ptr \00" +@.str420 = private unnamed_addr constant [2 x i8] c")\00" +@.str421 = private unnamed_addr constant [4 x i8] c"str\00" +@.str422 = private unnamed_addr constant [5 x i8] c"bnot\00" +@.str423 = private unnamed_addr constant [9 x i8] c"xor i32 \00" +@.str424 = private unnamed_addr constant [5 x i8] c", -1\00" +@.str425 = private unnamed_addr constant [4 x i8] c"int\00" +@.str426 = private unnamed_addr constant [4 x i8] c"shl\00" +@.str427 = private unnamed_addr constant [4 x i8] c"shr\00" +@.str428 = private unnamed_addr constant [5 x i8] c"band\00" +@.str429 = private unnamed_addr constant [4 x i8] c"bor\00" +@.str430 = private unnamed_addr constant [5 x i8] c"bxor\00" +@.str431 = private unnamed_addr constant [4 x i8] c"shl\00" +@.str432 = private unnamed_addr constant [4 x i8] c"shr\00" +@.str433 = private unnamed_addr constant [5 x i8] c"lshr\00" +@.str434 = private unnamed_addr constant [5 x i8] c"band\00" +@.str435 = private unnamed_addr constant [4 x i8] c"and\00" +@.str436 = private unnamed_addr constant [4 x i8] c"bor\00" +@.str437 = private unnamed_addr constant [3 x i8] c"or\00" +@.str438 = private unnamed_addr constant [5 x i8] c"bxor\00" +@.str439 = private unnamed_addr constant [4 x i8] c"xor\00" +@.str440 = private unnamed_addr constant [6 x i8] c" i32 \00" +@.str441 = private unnamed_addr constant [3 x i8] c", \00" +@.str442 = private unnamed_addr constant [4 x i8] c"int\00" +@.str443 = private unnamed_addr constant [7 x i8] c"peek32\00" +@.str444 = private unnamed_addr constant [3 x i8] c" \00" +@.str445 = private unnamed_addr constant [36 x i8] c" = getelementptr inbounds i32, ptr \00" +@.str446 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str447 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str448 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str449 = private unnamed_addr constant [4 x i8] c"int\00" +@.str450 = private unnamed_addr constant [7 x i8] c"poke32\00" +@.str451 = private unnamed_addr constant [3 x i8] c" \00" +@.str452 = private unnamed_addr constant [36 x i8] c" = getelementptr inbounds i32, ptr \00" +@.str453 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str454 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str455 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str456 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str457 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str458 = private unnamed_addr constant [2 x i8] c"0\00" +@.str459 = private unnamed_addr constant [5 x i8] c"void\00" +@.str460 = private unnamed_addr constant [2 x i8] c"0\00" +@.str461 = private unnamed_addr constant [5 x i8] c"void\00" +@.str462 = private unnamed_addr constant [9 x i8] c"mem_free\00" +@.str463 = private unnamed_addr constant [9 x i8] c"mem_copy\00" +@.str464 = private unnamed_addr constant [8 x i8] c"mem_set\00" +@.str465 = private unnamed_addr constant [8 x i8] c"ptr_add\00" +@.str466 = private unnamed_addr constant [10 x i8] c"read_byte\00" +@.str467 = private unnamed_addr constant [11 x i8] c"write_byte\00" +@.str468 = private unnamed_addr constant [8 x i8] c"str_len\00" +@.str469 = private unnamed_addr constant [8 x i8] c"os_time\00" +@.str470 = private unnamed_addr constant [6 x i8] c"peekf\00" +@.str471 = private unnamed_addr constant [6 x i8] c"pokef\00" +@.str472 = private unnamed_addr constant [9 x i8] c"as_fixed\00" +@.str473 = private unnamed_addr constant [7 x i8] c"as_int\00" +@.str474 = private unnamed_addr constant [6 x i8] c"peekp\00" +@.str475 = private unnamed_addr constant [6 x i8] c"pokep\00" +@.str476 = private unnamed_addr constant [12 x i8] c"is_windowed\00" +@.str477 = private unnamed_addr constant [11 x i8] c"game_title\00" +@.str478 = private unnamed_addr constant [9 x i8] c"win_open\00" +@.str479 = private unnamed_addr constant [9 x i8] c"win_poll\00" +@.str480 = private unnamed_addr constant [12 x i8] c"win_present\00" +@.str481 = private unnamed_addr constant [12 x i8] c"win_running\00" +@.str482 = private unnamed_addr constant [10 x i8] c"win_close\00" +@.str483 = private unnamed_addr constant [9 x i8] c"mem_free\00" +@.str484 = private unnamed_addr constant [23 x i8] c" call void @free(ptr \00" +@.str485 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str486 = private unnamed_addr constant [2 x i8] c"0\00" +@.str487 = private unnamed_addr constant [5 x i8] c"void\00" +@.str488 = private unnamed_addr constant [9 x i8] c"mem_copy\00" +@.str489 = private unnamed_addr constant [10 x i8] c"zext i32 \00" +@.str490 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str491 = private unnamed_addr constant [24 x i8] c" call ptr @memcpy(ptr \00" +@.str492 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str493 = private unnamed_addr constant [7 x i8] c", i64 \00" +@.str494 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str495 = private unnamed_addr constant [2 x i8] c"0\00" +@.str496 = private unnamed_addr constant [5 x i8] c"void\00" +@.str497 = private unnamed_addr constant [8 x i8] c"mem_set\00" +@.str498 = private unnamed_addr constant [10 x i8] c"zext i32 \00" +@.str499 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str500 = private unnamed_addr constant [24 x i8] c" call ptr @memset(ptr \00" +@.str501 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str502 = private unnamed_addr constant [7 x i8] c", i64 \00" +@.str503 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str504 = private unnamed_addr constant [2 x i8] c"0\00" +@.str505 = private unnamed_addr constant [5 x i8] c"void\00" +@.str506 = private unnamed_addr constant [8 x i8] c"ptr_add\00" +@.str507 = private unnamed_addr constant [3 x i8] c" \00" +@.str508 = private unnamed_addr constant [35 x i8] c" = getelementptr inbounds i8, ptr \00" +@.str509 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str510 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str511 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str512 = private unnamed_addr constant [10 x i8] c"read_byte\00" +@.str513 = private unnamed_addr constant [20 x i8] c"call i32 @getchar()\00" +@.str514 = private unnamed_addr constant [4 x i8] c"int\00" +@.str515 = private unnamed_addr constant [11 x i8] c"write_byte\00" +@.str516 = private unnamed_addr constant [25 x i8] c" call i32 @putchar(i32 \00" +@.str517 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str518 = private unnamed_addr constant [2 x i8] c"0\00" +@.str519 = private unnamed_addr constant [5 x i8] c"void\00" +@.str520 = private unnamed_addr constant [8 x i8] c"str_len\00" +@.str521 = private unnamed_addr constant [22 x i8] c"call i64 @strlen(ptr \00" +@.str522 = private unnamed_addr constant [2 x i8] c")\00" +@.str523 = private unnamed_addr constant [11 x i8] c"trunc i64 \00" +@.str524 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str525 = private unnamed_addr constant [4 x i8] c"int\00" +@.str526 = private unnamed_addr constant [8 x i8] c"os_time\00" +@.str527 = private unnamed_addr constant [25 x i8] c"call i64 @time(ptr null)\00" +@.str528 = private unnamed_addr constant [11 x i8] c"trunc i64 \00" +@.str529 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str530 = private unnamed_addr constant [4 x i8] c"int\00" +@.str531 = private unnamed_addr constant [6 x i8] c"peekf\00" +@.str532 = private unnamed_addr constant [3 x i8] c" \00" +@.str533 = private unnamed_addr constant [36 x i8] c" = getelementptr inbounds i32, ptr \00" +@.str534 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str535 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str536 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str537 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str538 = private unnamed_addr constant [6 x i8] c"pokef\00" +@.str539 = private unnamed_addr constant [3 x i8] c" \00" +@.str540 = private unnamed_addr constant [36 x i8] c" = getelementptr inbounds i32, ptr \00" +@.str541 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str542 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str543 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str544 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str545 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str546 = private unnamed_addr constant [2 x i8] c"0\00" +@.str547 = private unnamed_addr constant [5 x i8] c"void\00" +@.str548 = private unnamed_addr constant [6 x i8] c"peekp\00" +@.str549 = private unnamed_addr constant [3 x i8] c" \00" +@.str550 = private unnamed_addr constant [36 x i8] c" = getelementptr inbounds ptr, ptr \00" +@.str551 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str552 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str553 = private unnamed_addr constant [15 x i8] c"load ptr, ptr \00" +@.str554 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str555 = private unnamed_addr constant [6 x i8] c"pokep\00" +@.str556 = private unnamed_addr constant [3 x i8] c" \00" +@.str557 = private unnamed_addr constant [36 x i8] c" = getelementptr inbounds ptr, ptr \00" +@.str558 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str559 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str560 = private unnamed_addr constant [13 x i8] c" store ptr \00" +@.str561 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str562 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str563 = private unnamed_addr constant [2 x i8] c"0\00" +@.str564 = private unnamed_addr constant [5 x i8] c"void\00" +@.str565 = private unnamed_addr constant [9 x i8] c"as_fixed\00" +@.str566 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str567 = private unnamed_addr constant [7 x i8] c"as_int\00" +@.str568 = private unnamed_addr constant [4 x i8] c"int\00" +@.str569 = private unnamed_addr constant [12 x i8] c"is_windowed\00" +@.str570 = private unnamed_addr constant [2 x i8] c"1\00" +@.str571 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str572 = private unnamed_addr constant [2 x i8] c"0\00" +@.str573 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str574 = private unnamed_addr constant [11 x i8] c"game_title\00" +@.str575 = private unnamed_addr constant [12 x i8] c"@.gametitle\00" +@.str576 = private unnamed_addr constant [4 x i8] c"str\00" +@.str577 = private unnamed_addr constant [9 x i8] c"win_poll\00" +@.str578 = private unnamed_addr constant [21 x i8] c"call i32 @win_poll()\00" +@.str579 = private unnamed_addr constant [4 x i8] c"int\00" +@.str580 = private unnamed_addr constant [12 x i8] c"win_running\00" +@.str581 = private unnamed_addr constant [24 x i8] c"call i32 @win_running()\00" +@.str582 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str583 = private unnamed_addr constant [9 x i8] c"win_open\00" +@.str584 = private unnamed_addr constant [27 x i8] c" call void @win_open(i32 \00" +@.str585 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str586 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str587 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str588 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str589 = private unnamed_addr constant [2 x i8] c"0\00" +@.str590 = private unnamed_addr constant [5 x i8] c"void\00" +@.str591 = private unnamed_addr constant [12 x i8] c"win_present\00" +@.str592 = private unnamed_addr constant [30 x i8] c" call void @win_present(ptr \00" +@.str593 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str594 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str595 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str596 = private unnamed_addr constant [2 x i8] c"0\00" +@.str597 = private unnamed_addr constant [5 x i8] c"void\00" +@.str598 = private unnamed_addr constant [10 x i8] c"win_close\00" +@.str599 = private unnamed_addr constant [26 x i8] c" call void @win_close()\0A\00" +@.str600 = private unnamed_addr constant [2 x i8] c"0\00" +@.str601 = private unnamed_addr constant [5 x i8] c"void\00" +@.str602 = private unnamed_addr constant [2 x i8] c"0\00" +@.str603 = private unnamed_addr constant [5 x i8] c"void\00" +@.str604 = private unnamed_addr constant [4 x i8] c"min\00" +@.str605 = private unnamed_addr constant [4 x i8] c"max\00" +@.str606 = private unnamed_addr constant [4 x i8] c"abs\00" +@.str607 = private unnamed_addr constant [6 x i8] c"clamp\00" +@.str608 = private unnamed_addr constant [4 x i8] c"abs\00" +@.str609 = private unnamed_addr constant [14 x i8] c"icmp slt i32 \00" +@.str610 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str611 = private unnamed_addr constant [12 x i8] c"sub i32 0, \00" +@.str612 = private unnamed_addr constant [11 x i8] c"select i1 \00" +@.str613 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str614 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str615 = private unnamed_addr constant [4 x i8] c"int\00" +@.str616 = private unnamed_addr constant [4 x i8] c"min\00" +@.str617 = private unnamed_addr constant [4 x i8] c"max\00" +@.str618 = private unnamed_addr constant [4 x i8] c"slt\00" +@.str619 = private unnamed_addr constant [4 x i8] c"max\00" +@.str620 = private unnamed_addr constant [4 x i8] c"sgt\00" +@.str621 = private unnamed_addr constant [6 x i8] c"icmp \00" +@.str622 = private unnamed_addr constant [6 x i8] c" i32 \00" +@.str623 = private unnamed_addr constant [3 x i8] c", \00" +@.str624 = private unnamed_addr constant [11 x i8] c"select i1 \00" +@.str625 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str626 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str627 = private unnamed_addr constant [4 x i8] c"int\00" +@.str628 = private unnamed_addr constant [14 x i8] c"icmp slt i32 \00" +@.str629 = private unnamed_addr constant [3 x i8] c", \00" +@.str630 = private unnamed_addr constant [11 x i8] c"select i1 \00" +@.str631 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str632 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str633 = private unnamed_addr constant [14 x i8] c"icmp sgt i32 \00" +@.str634 = private unnamed_addr constant [3 x i8] c", \00" +@.str635 = private unnamed_addr constant [11 x i8] c"select i1 \00" +@.str636 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str637 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str638 = private unnamed_addr constant [4 x i8] c"int\00" +@.str639 = private unnamed_addr constant [15 x i8] c"getelementptr \00" +@.str640 = private unnamed_addr constant [18 x i8] c", ptr null, i32 1\00" +@.str641 = private unnamed_addr constant [14 x i8] c"ptrtoint ptr \00" +@.str642 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str643 = private unnamed_addr constant [22 x i8] c"unknown struct in new\00" +@.str644 = private unnamed_addr constant [6 x i8] c"%Str_\00" +@.str645 = private unnamed_addr constant [22 x i8] c"call ptr @malloc(i64 \00" +@.str646 = private unnamed_addr constant [2 x i8] c")\00" +@.str647 = private unnamed_addr constant [3 x i8] c" \00" +@.str648 = private unnamed_addr constant [32 x i8] c" = getelementptr inbounds %Str_\00" +@.str649 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str650 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str651 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str652 = private unnamed_addr constant [2 x i8] c"0\00" +@.str653 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str654 = private unnamed_addr constant [5 x i8] c"null\00" +@.str655 = private unnamed_addr constant [9 x i8] c" store \00" +@.str656 = private unnamed_addr constant [2 x i8] c" \00" +@.str657 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str658 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str659 = private unnamed_addr constant [8 x i8] c"%LSlice\00" +@.str660 = private unnamed_addr constant [22 x i8] c"call ptr @malloc(i64 \00" +@.str661 = private unnamed_addr constant [2 x i8] c")\00" +@.str662 = private unnamed_addr constant [3 x i8] c" \00" +@.str663 = private unnamed_addr constant [40 x i8] c" = getelementptr inbounds %LSlice, ptr \00" +@.str664 = private unnamed_addr constant [16 x i8] c", i32 0, i32 0\0A\00" +@.str665 = private unnamed_addr constant [23 x i8] c" store ptr null, ptr \00" +@.str666 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str667 = private unnamed_addr constant [3 x i8] c" \00" +@.str668 = private unnamed_addr constant [40 x i8] c" = getelementptr inbounds %LSlice, ptr \00" +@.str669 = private unnamed_addr constant [16 x i8] c", i32 0, i32 1\0A\00" +@.str670 = private unnamed_addr constant [20 x i8] c" store i32 0, ptr \00" +@.str671 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str672 = private unnamed_addr constant [3 x i8] c" \00" +@.str673 = private unnamed_addr constant [40 x i8] c" = getelementptr inbounds %LSlice, ptr \00" +@.str674 = private unnamed_addr constant [16 x i8] c", i32 0, i32 2\0A\00" +@.str675 = private unnamed_addr constant [20 x i8] c" store i32 0, ptr \00" +@.str676 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str677 = private unnamed_addr constant [3 x i8] c" \00" +@.str678 = private unnamed_addr constant [40 x i8] c" = getelementptr inbounds %LSlice, ptr \00" +@.str679 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str680 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str681 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str682 = private unnamed_addr constant [4 x i8] c"int\00" +@.str683 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str684 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str685 = private unnamed_addr constant [14 x i8] c"icmp sge i32 \00" +@.str686 = private unnamed_addr constant [3 x i8] c", \00" +@.str687 = private unnamed_addr constant [5 x i8] c"grow\00" +@.str688 = private unnamed_addr constant [4 x i8] c"put\00" +@.str689 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str690 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str691 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str692 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str693 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str694 = private unnamed_addr constant [9 x i8] c"mul i32 \00" +@.str695 = private unnamed_addr constant [4 x i8] c", 2\00" +@.str696 = private unnamed_addr constant [13 x i8] c"icmp eq i32 \00" +@.str697 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str698 = private unnamed_addr constant [11 x i8] c"select i1 \00" +@.str699 = private unnamed_addr constant [14 x i8] c", i32 8, i32 \00" +@.str700 = private unnamed_addr constant [10 x i8] c"zext i32 \00" +@.str701 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str702 = private unnamed_addr constant [9 x i8] c"mul i64 \00" +@.str703 = private unnamed_addr constant [3 x i8] c", \00" +@.str704 = private unnamed_addr constant [15 x i8] c"load ptr, ptr \00" +@.str705 = private unnamed_addr constant [23 x i8] c"call ptr @realloc(ptr \00" +@.str706 = private unnamed_addr constant [7 x i8] c", i64 \00" +@.str707 = private unnamed_addr constant [2 x i8] c")\00" +@.str708 = private unnamed_addr constant [13 x i8] c" store ptr \00" +@.str709 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str710 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str711 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str712 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str713 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str714 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str715 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str716 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str717 = private unnamed_addr constant [15 x i8] c"load ptr, ptr \00" +@.str718 = private unnamed_addr constant [3 x i8] c" \00" +@.str719 = private unnamed_addr constant [27 x i8] c" = getelementptr inbounds \00" +@.str720 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str721 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str722 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str723 = private unnamed_addr constant [9 x i8] c" store \00" +@.str724 = private unnamed_addr constant [2 x i8] c" \00" +@.str725 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str726 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str727 = private unnamed_addr constant [9 x i8] c"add i32 \00" +@.str728 = private unnamed_addr constant [4 x i8] c", 1\00" +@.str729 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str730 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str731 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str732 = private unnamed_addr constant [2 x i8] c"0\00" +@.str733 = private unnamed_addr constant [5 x i8] c"void\00" +@.str734 = private unnamed_addr constant [6 x i8] c"load \00" +@.str735 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str736 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str737 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str738 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str739 = private unnamed_addr constant [9 x i8] c"zext i1 \00" +@.str740 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str741 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str742 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str743 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str744 = private unnamed_addr constant [3 x i8] c"sc\00" +@.str745 = private unnamed_addr constant [6 x i8] c"scend\00" +@.str746 = private unnamed_addr constant [4 x i8] c"and\00" +@.str747 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str748 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str749 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str750 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str751 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str752 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str753 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str754 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str755 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str756 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str757 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str758 = private unnamed_addr constant [9 x i8] c"zext i1 \00" +@.str759 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str760 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str761 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str762 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str763 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str764 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str765 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str766 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str767 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str768 = private unnamed_addr constant [2 x i8] c"<\00" +@.str769 = private unnamed_addr constant [4 x i8] c"slt\00" +@.str770 = private unnamed_addr constant [3 x i8] c"<=\00" +@.str771 = private unnamed_addr constant [4 x i8] c"sle\00" +@.str772 = private unnamed_addr constant [2 x i8] c">\00" +@.str773 = private unnamed_addr constant [4 x i8] c"sgt\00" +@.str774 = private unnamed_addr constant [3 x i8] c">=\00" +@.str775 = private unnamed_addr constant [4 x i8] c"sge\00" +@.str776 = private unnamed_addr constant [3 x i8] c"==\00" +@.str777 = private unnamed_addr constant [3 x i8] c"eq\00" +@.str778 = private unnamed_addr constant [3 x i8] c"ne\00" +@.str779 = private unnamed_addr constant [2 x i8] c"<\00" +@.str780 = private unnamed_addr constant [3 x i8] c"<=\00" +@.str781 = private unnamed_addr constant [2 x i8] c">\00" +@.str782 = private unnamed_addr constant [3 x i8] c">=\00" +@.str783 = private unnamed_addr constant [3 x i8] c"==\00" +@.str784 = private unnamed_addr constant [3 x i8] c"!=\00" +@.str785 = private unnamed_addr constant [2 x i8] c"+\00" +@.str786 = private unnamed_addr constant [4 x i8] c"add\00" +@.str787 = private unnamed_addr constant [2 x i8] c"-\00" +@.str788 = private unnamed_addr constant [4 x i8] c"sub\00" +@.str789 = private unnamed_addr constant [2 x i8] c"*\00" +@.str790 = private unnamed_addr constant [4 x i8] c"mul\00" +@.str791 = private unnamed_addr constant [2 x i8] c"/\00" +@.str792 = private unnamed_addr constant [5 x i8] c"sdiv\00" +@.str793 = private unnamed_addr constant [5 x i8] c"srem\00" +@.str794 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str795 = private unnamed_addr constant [9 x i8] c"shl i32 \00" +@.str796 = private unnamed_addr constant [5 x i8] c", 16\00" +@.str797 = private unnamed_addr constant [4 x i8] c"and\00" +@.str798 = private unnamed_addr constant [3 x i8] c"or\00" +@.str799 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str800 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str801 = private unnamed_addr constant [6 x i8] c"icmp \00" +@.str802 = private unnamed_addr constant [6 x i8] c" i32 \00" +@.str803 = private unnamed_addr constant [3 x i8] c", \00" +@.str804 = private unnamed_addr constant [9 x i8] c"zext i1 \00" +@.str805 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str806 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str807 = private unnamed_addr constant [2 x i8] c"*\00" +@.str808 = private unnamed_addr constant [10 x i8] c"sext i32 \00" +@.str809 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str810 = private unnamed_addr constant [10 x i8] c"sext i32 \00" +@.str811 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str812 = private unnamed_addr constant [9 x i8] c"mul i64 \00" +@.str813 = private unnamed_addr constant [3 x i8] c", \00" +@.str814 = private unnamed_addr constant [10 x i8] c"ashr i64 \00" +@.str815 = private unnamed_addr constant [5 x i8] c", 16\00" +@.str816 = private unnamed_addr constant [11 x i8] c"trunc i64 \00" +@.str817 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str818 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str819 = private unnamed_addr constant [2 x i8] c"/\00" +@.str820 = private unnamed_addr constant [10 x i8] c"sext i32 \00" +@.str821 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str822 = private unnamed_addr constant [9 x i8] c"shl i64 \00" +@.str823 = private unnamed_addr constant [5 x i8] c", 16\00" +@.str824 = private unnamed_addr constant [10 x i8] c"sext i32 \00" +@.str825 = private unnamed_addr constant [8 x i8] c" to i64\00" +@.str826 = private unnamed_addr constant [10 x i8] c"sdiv i64 \00" +@.str827 = private unnamed_addr constant [3 x i8] c", \00" +@.str828 = private unnamed_addr constant [11 x i8] c"trunc i64 \00" +@.str829 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str830 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str831 = private unnamed_addr constant [6 x i8] c" i32 \00" +@.str832 = private unnamed_addr constant [3 x i8] c", \00" +@.str833 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str834 = private unnamed_addr constant [6 x i8] c" i32 \00" +@.str835 = private unnamed_addr constant [3 x i8] c", \00" +@.str836 = private unnamed_addr constant [4 x i8] c"int\00" +@.str837 = private unnamed_addr constant [5 x i8] c"self\00" +@.str838 = private unnamed_addr constant [2 x i8] c"0\00" +@.str839 = private unnamed_addr constant [7 x i8] c"entity\00" +@.str840 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str841 = private unnamed_addr constant [7 x i8] c"entity\00" +@.str842 = private unnamed_addr constant [4 x i8] c"key\00" +@.str843 = private unnamed_addr constant [21 x i8] c"load i32, ptr @L_key\00" +@.str844 = private unnamed_addr constant [4 x i8] c"int\00" +@.str845 = private unnamed_addr constant [5 x i8] c"save\00" +@.str846 = private unnamed_addr constant [23 x i8] c" call void @L_save()\0A\00" +@.str847 = private unnamed_addr constant [2 x i8] c"0\00" +@.str848 = private unnamed_addr constant [5 x i8] c"void\00" +@.str849 = private unnamed_addr constant [9 x i8] c"ui_build\00" +@.str850 = private unnamed_addr constant [25 x i8] c" call void @ui_build()\0A\00" +@.str851 = private unnamed_addr constant [2 x i8] c"0\00" +@.str852 = private unnamed_addr constant [5 x i8] c"void\00" +@.str853 = private unnamed_addr constant [5 x i8] c"load\00" +@.str854 = private unnamed_addr constant [19 x i8] c"call i32 @L_load()\00" +@.str855 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str856 = private unnamed_addr constant [5 x i8] c"quit\00" +@.str857 = private unnamed_addr constant [31 x i8] c" store i32 0, ptr @L_running\0A\00" +@.str858 = private unnamed_addr constant [2 x i8] c"0\00" +@.str859 = private unnamed_addr constant [5 x i8] c"void\00" +@.str860 = private unnamed_addr constant [4 x i8] c"len\00" +@.str861 = private unnamed_addr constant [5 x i8] c"push\00" +@.str862 = private unnamed_addr constant [3 x i8] c"fx\00" +@.str863 = private unnamed_addr constant [9 x i8] c"shl i32 \00" +@.str864 = private unnamed_addr constant [5 x i8] c", 16\00" +@.str865 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str866 = private unnamed_addr constant [4 x i8] c"flr\00" +@.str867 = private unnamed_addr constant [10 x i8] c"ashr i32 \00" +@.str868 = private unnamed_addr constant [5 x i8] c", 16\00" +@.str869 = private unnamed_addr constant [4 x i8] c"int\00" +@.str870 = private unnamed_addr constant [4 x i8] c"rt_\00" +@.str871 = private unnamed_addr constant [18 x i8] c"unknown function \00" +@.str872 = private unnamed_addr constant [3 x i8] c" \00" +@.str873 = private unnamed_addr constant [2 x i8] c"0\00" +@.str874 = private unnamed_addr constant [5 x i8] c"void\00" +@.str875 = private unnamed_addr constant [4 x i8] c" = \00" +@.str876 = private unnamed_addr constant [6 x i8] c"call \00" +@.str877 = private unnamed_addr constant [6 x i8] c" @fn_\00" +@.str878 = private unnamed_addr constant [2 x i8] c"(\00" +@.str879 = private unnamed_addr constant [3 x i8] c", \00" +@.str880 = private unnamed_addr constant [2 x i8] c" \00" +@.str881 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str882 = private unnamed_addr constant [2 x i8] c"0\00" +@.str883 = private unnamed_addr constant [4 x i8] c"int\00" +@.str884 = private unnamed_addr constant [4 x i8] c"int\00" +@.str885 = private unnamed_addr constant [6 x i8] c"fixed\00" +@.str886 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str887 = private unnamed_addr constant [4 x i8] c"str\00" +@.str888 = private unnamed_addr constant [4 x i8] c"int\00" +@.str889 = private unnamed_addr constant [6 x i8] c"load \00" +@.str890 = private unnamed_addr constant [10 x i8] c", ptr @g_\00" +@.str891 = private unnamed_addr constant [4 x i8] c"int\00" +@.str892 = private unnamed_addr constant [20 x i8] c"unknown identifier \00" +@.str893 = private unnamed_addr constant [2 x i8] c"-\00" +@.str894 = private unnamed_addr constant [12 x i8] c"sub i32 0, \00" +@.str895 = private unnamed_addr constant [4 x i8] c"int\00" +@.str896 = private unnamed_addr constant [13 x i8] c"icmp eq i32 \00" +@.str897 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str898 = private unnamed_addr constant [9 x i8] c"zext i1 \00" +@.str899 = private unnamed_addr constant [8 x i8] c" to i32\00" +@.str900 = private unnamed_addr constant [5 x i8] c"bool\00" +@.str901 = private unnamed_addr constant [23 x i8] c"cannot emit expression\00" +@.str902 = private unnamed_addr constant [2 x i8] c"0\00" +@.str903 = private unnamed_addr constant [4 x i8] c"int\00" +@.str904 = private unnamed_addr constant [9 x i8] c" store \00" +@.str905 = private unnamed_addr constant [2 x i8] c" \00" +@.str906 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str907 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str908 = private unnamed_addr constant [2 x i8] c"0\00" +@.str909 = private unnamed_addr constant [4 x i8] c"int\00" +@.str910 = private unnamed_addr constant [19 x i8] c"assign to unknown \00" +@.str911 = private unnamed_addr constant [4 x i8] c"@g_\00" +@.str912 = private unnamed_addr constant [22 x i8] c"bad assignment target\00" +@.str913 = private unnamed_addr constant [2 x i8] c"=\00" +@.str914 = private unnamed_addr constant [6 x i8] c"load \00" +@.str915 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str916 = private unnamed_addr constant [4 x i8] c"add\00" +@.str917 = private unnamed_addr constant [3 x i8] c"-=\00" +@.str918 = private unnamed_addr constant [4 x i8] c"sub\00" +@.str919 = private unnamed_addr constant [3 x i8] c"*=\00" +@.str920 = private unnamed_addr constant [4 x i8] c"mul\00" +@.str921 = private unnamed_addr constant [3 x i8] c"/=\00" +@.str922 = private unnamed_addr constant [5 x i8] c"sdiv\00" +@.str923 = private unnamed_addr constant [6 x i8] c" i32 \00" +@.str924 = private unnamed_addr constant [3 x i8] c", \00" +@.str925 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str926 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str927 = private unnamed_addr constant [5 x i8] c"then\00" +@.str928 = private unnamed_addr constant [5 x i8] c"else\00" +@.str929 = private unnamed_addr constant [6 x i8] c"ifend\00" +@.str930 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str931 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str932 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str933 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str934 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str935 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str936 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str937 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str938 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str939 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str940 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str941 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str942 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str943 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str944 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str945 = private unnamed_addr constant [6 x i8] c"wcond\00" +@.str946 = private unnamed_addr constant [6 x i8] c"wbody\00" +@.str947 = private unnamed_addr constant [5 x i8] c"wend\00" +@.str948 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str949 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str950 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str951 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str952 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str953 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str954 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str955 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str956 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str957 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str958 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str959 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str960 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str961 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str962 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str963 = private unnamed_addr constant [4 x i8] c"int\00" +@.str964 = private unnamed_addr constant [6 x i8] c"fcond\00" +@.str965 = private unnamed_addr constant [6 x i8] c"fbody\00" +@.str966 = private unnamed_addr constant [6 x i8] c"fcont\00" +@.str967 = private unnamed_addr constant [5 x i8] c"fend\00" +@.str968 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str969 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str970 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str971 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str972 = private unnamed_addr constant [14 x i8] c"icmp slt i32 \00" +@.str973 = private unnamed_addr constant [3 x i8] c", \00" +@.str974 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str975 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str976 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str977 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str978 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str979 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str980 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str981 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str982 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str983 = private unnamed_addr constant [9 x i8] c"add i32 \00" +@.str984 = private unnamed_addr constant [4 x i8] c", 1\00" +@.str985 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str986 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str987 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str988 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str989 = private unnamed_addr constant [8 x i8] c"%retval\00" +@.str990 = private unnamed_addr constant [17 x i8] c" br label %ret\0A\00" +@.str991 = private unnamed_addr constant [2 x i8] c"_\00" +@.str992 = private unnamed_addr constant [5 x i8] c"mend\00" +@.str993 = private unnamed_addr constant [2 x i8] c"0\00" +@.str994 = private unnamed_addr constant [13 x i8] c"icmp eq i32 \00" +@.str995 = private unnamed_addr constant [3 x i8] c", \00" +@.str996 = private unnamed_addr constant [7 x i8] c"or i1 \00" +@.str997 = private unnamed_addr constant [3 x i8] c", \00" +@.str998 = private unnamed_addr constant [6 x i8] c"mbody\00" +@.str999 = private unnamed_addr constant [5 x i8] c"marm\00" +@.str1000 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1001 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1002 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1003 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1004 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1005 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1006 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1007 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1008 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1009 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1010 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1011 = private unnamed_addr constant [2 x i8] c"0\00" +@.str1012 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str1013 = private unnamed_addr constant [5 x i8] c"null\00" +@.str1014 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1015 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1016 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1017 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1018 = private unnamed_addr constant [22 x i8] c"cannot emit statement\00" +@.str1019 = private unnamed_addr constant [36 x i8] c"@L_running = internal global i32 1\0A\00" +@.str1020 = private unnamed_addr constant [32 x i8] c"@L_key = internal global i32 0\0A\00" +@.str1021 = private unnamed_addr constant [33 x i8] c"@L_entc = internal global i32 0\0A\00" +@.str1022 = private unnamed_addr constant [29 x i8] c"@L_alive = internal global [\00" +@.str1023 = private unnamed_addr constant [25 x i8] c" x i32] zeroinitializer\0A\00" +@.str1024 = private unnamed_addr constant [28 x i8] c"@L_kind = internal global [\00" +@.str1025 = private unnamed_addr constant [25 x i8] c" x i32] zeroinitializer\0A\00" +@.str1026 = private unnamed_addr constant [32 x i8] c"@L_freelist = internal global [\00" +@.str1027 = private unnamed_addr constant [25 x i8] c" x i32] zeroinitializer\0A\00" +@.str1028 = private unnamed_addr constant [34 x i8] c"@L_freen = internal global i32 0\0A\00" +@.str1029 = private unnamed_addr constant [6 x i8] c"%Cmp_\00" +@.str1030 = private unnamed_addr constant [11 x i8] c" = type { \00" +@.str1031 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str1032 = private unnamed_addr constant [3 x i8] c", \00" +@.str1033 = private unnamed_addr constant [4 x i8] c" }\0A\00" +@.str1034 = private unnamed_addr constant [4 x i8] c"@S_\00" +@.str1035 = private unnamed_addr constant [21 x i8] c" = internal global [\00" +@.str1036 = private unnamed_addr constant [9 x i8] c" x %Cmp_\00" +@.str1037 = private unnamed_addr constant [19 x i8] c"] zeroinitializer\0A\00" +@.str1038 = private unnamed_addr constant [4 x i8] c"@H_\00" +@.str1039 = private unnamed_addr constant [21 x i8] c" = internal global [\00" +@.str1040 = private unnamed_addr constant [24 x i8] c" x i8] zeroinitializer\0A\00" +@.str1041 = private unnamed_addr constant [39 x i8] c"define void @L_reset(i32 %e) {\0Aentry:\0A\00" +@.str1042 = private unnamed_addr constant [3 x i8] c"%h\00" +@.str1043 = private unnamed_addr constant [3 x i8] c" \00" +@.str1044 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1045 = private unnamed_addr constant [16 x i8] c" x i8], ptr @H_\00" +@.str1046 = private unnamed_addr constant [17 x i8] c", i32 0, i32 %e\0A\00" +@.str1047 = private unnamed_addr constant [19 x i8] c" store i8 0, ptr \00" +@.str1048 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1049 = private unnamed_addr constant [32 x i8] c" %k = getelementptr inbounds [\00" +@.str1050 = private unnamed_addr constant [37 x i8] c" x i32], ptr @L_kind, i32 0, i32 %e\0A\00" +@.str1051 = private unnamed_addr constant [37 x i8] c" store i32 0, ptr %k\0A ret void\0A}\0A\0A\00" +@.str1052 = private unnamed_addr constant [32 x i8] c"define i32 @L_alloc() {\0Aentry:\0A\00" +@.str1053 = private unnamed_addr constant [32 x i8] c" %fn = load i32, ptr @L_freen\0A\00" +@.str1054 = private unnamed_addr constant [30 x i8] c" %has = icmp sgt i32 %fn, 0\0A\00" +@.str1055 = private unnamed_addr constant [42 x i8] c" br i1 %has, label %reuse, label %fresh\0A\00" +@.str1056 = private unnamed_addr constant [8 x i8] c"reuse:\0A\00" +@.str1057 = private unnamed_addr constant [25 x i8] c" %fn1 = sub i32 %fn, 1\0A\00" +@.str1058 = private unnamed_addr constant [32 x i8] c" store i32 %fn1, ptr @L_freen\0A\00" +@.str1059 = private unnamed_addr constant [33 x i8] c" %fp = getelementptr inbounds [\00" +@.str1060 = private unnamed_addr constant [43 x i8] c" x i32], ptr @L_freelist, i32 0, i32 %fn1\0A\00" +@.str1061 = private unnamed_addr constant [27 x i8] c" %re = load i32, ptr %fp\0A\00" +@.str1062 = private unnamed_addr constant [18 x i8] c" br label %done\0A\00" +@.str1063 = private unnamed_addr constant [8 x i8] c"fresh:\0A\00" +@.str1064 = private unnamed_addr constant [31 x i8] c" %ec = load i32, ptr @L_entc\0A\00" +@.str1065 = private unnamed_addr constant [25 x i8] c" %ec1 = add i32 %ec, 1\0A\00" +@.str1066 = private unnamed_addr constant [31 x i8] c" store i32 %ec1, ptr @L_entc\0A\00" +@.str1067 = private unnamed_addr constant [18 x i8] c" br label %done\0A\00" +@.str1068 = private unnamed_addr constant [7 x i8] c"done:\0A\00" +@.str1069 = private unnamed_addr constant [49 x i8] c" %e = phi i32 [ %re, %reuse ], [ %ec, %fresh ]\0A\00" +@.str1070 = private unnamed_addr constant [30 x i8] c" call void @L_reset(i32 %e)\0A\00" +@.str1071 = private unnamed_addr constant [33 x i8] c" %ap = getelementptr inbounds [\00" +@.str1072 = private unnamed_addr constant [38 x i8] c" x i32], ptr @L_alive, i32 0, i32 %e\0A\00" +@.str1073 = private unnamed_addr constant [24 x i8] c" store i32 1, ptr %ap\0A\00" +@.str1074 = private unnamed_addr constant [17 x i8] c" ret i32 %e\0A}\0A\0A\00" +@.str1075 = private unnamed_addr constant [45 x i8] c"define void @L_free_entity(i32 %e) {\0Aentry:\0A\00" +@.str1076 = private unnamed_addr constant [33 x i8] c" %ap = getelementptr inbounds [\00" +@.str1077 = private unnamed_addr constant [38 x i8] c" x i32], ptr @L_alive, i32 0, i32 %e\0A\00" +@.str1078 = private unnamed_addr constant [24 x i8] c" store i32 0, ptr %ap\0A\00" +@.str1079 = private unnamed_addr constant [30 x i8] c" call void @L_reset(i32 %e)\0A\00" +@.str1080 = private unnamed_addr constant [32 x i8] c" %fn = load i32, ptr @L_freen\0A\00" +@.str1081 = private unnamed_addr constant [33 x i8] c" %fp = getelementptr inbounds [\00" +@.str1082 = private unnamed_addr constant [42 x i8] c" x i32], ptr @L_freelist, i32 0, i32 %fn\0A\00" +@.str1083 = private unnamed_addr constant [25 x i8] c" store i32 %e, ptr %fp\0A\00" +@.str1084 = private unnamed_addr constant [25 x i8] c" %fn1 = add i32 %fn, 1\0A\00" +@.str1085 = private unnamed_addr constant [32 x i8] c" store i32 %fn1, ptr @L_freen\0A\00" +@.str1086 = private unnamed_addr constant [15 x i8] c" ret void\0A}\0A\0A\00" +@.str1087 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str1088 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str1089 = private unnamed_addr constant [2 x i8] c"0\00" +@.str1090 = private unnamed_addr constant [6 x i8] c"qcond\00" +@.str1091 = private unnamed_addr constant [6 x i8] c"qbody\00" +@.str1092 = private unnamed_addr constant [6 x i8] c"qnext\00" +@.str1093 = private unnamed_addr constant [5 x i8] c"qend\00" +@.str1094 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1095 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1096 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1097 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str1098 = private unnamed_addr constant [22 x i8] c"load i32, ptr @L_entc\00" +@.str1099 = private unnamed_addr constant [14 x i8] c"icmp slt i32 \00" +@.str1100 = private unnamed_addr constant [3 x i8] c", \00" +@.str1101 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1102 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1103 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1104 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1105 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1106 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str1107 = private unnamed_addr constant [3 x i8] c" \00" +@.str1108 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1109 = private unnamed_addr constant [35 x i8] c" x i32], ptr @L_alive, i32 0, i32 \00" +@.str1110 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1111 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str1112 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str1113 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str1114 = private unnamed_addr constant [3 x i8] c"qa\00" +@.str1115 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1116 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1117 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1118 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1119 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1120 = private unnamed_addr constant [2 x i8] c"0\00" +@.str1121 = private unnamed_addr constant [3 x i8] c" \00" +@.str1122 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1123 = private unnamed_addr constant [34 x i8] c" x i32], ptr @L_kind, i32 0, i32 \00" +@.str1124 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1125 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str1126 = private unnamed_addr constant [13 x i8] c"icmp eq i32 \00" +@.str1127 = private unnamed_addr constant [3 x i8] c", \00" +@.str1128 = private unnamed_addr constant [3 x i8] c" \00" +@.str1129 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1130 = private unnamed_addr constant [16 x i8] c" x i8], ptr @H_\00" +@.str1131 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str1132 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1133 = private unnamed_addr constant [14 x i8] c"load i8, ptr \00" +@.str1134 = private unnamed_addr constant [12 x i8] c"icmp ne i8 \00" +@.str1135 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str1136 = private unnamed_addr constant [3 x i8] c"qt\00" +@.str1137 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1138 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1139 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1140 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1141 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1142 = private unnamed_addr constant [3 x i8] c" \00" +@.str1143 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1144 = private unnamed_addr constant [9 x i8] c" x %Cmp_\00" +@.str1145 = private unnamed_addr constant [11 x i8] c"], ptr @S_\00" +@.str1146 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str1147 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1148 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str1149 = private unnamed_addr constant [13 x i8] c" store ptr \00" +@.str1150 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1151 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1152 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str1153 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str1154 = private unnamed_addr constant [3 x i8] c"qw\00" +@.str1155 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1156 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1157 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1158 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1159 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1160 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1161 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1162 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1163 = private unnamed_addr constant [15 x i8] c"load i32, ptr \00" +@.str1164 = private unnamed_addr constant [9 x i8] c"add i32 \00" +@.str1165 = private unnamed_addr constant [4 x i8] c", 1\00" +@.str1166 = private unnamed_addr constant [4 x i8] c"i32\00" +@.str1167 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1168 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1169 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1170 = private unnamed_addr constant [26 x i8] c"spawn: unknown component \00" +@.str1171 = private unnamed_addr constant [3 x i8] c" \00" +@.str1172 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1173 = private unnamed_addr constant [16 x i8] c" x i8], ptr @H_\00" +@.str1174 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str1175 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1176 = private unnamed_addr constant [19 x i8] c" store i8 1, ptr \00" +@.str1177 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1178 = private unnamed_addr constant [3 x i8] c" \00" +@.str1179 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1180 = private unnamed_addr constant [9 x i8] c" x %Cmp_\00" +@.str1181 = private unnamed_addr constant [11 x i8] c"], ptr @S_\00" +@.str1182 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str1183 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1184 = private unnamed_addr constant [3 x i8] c" \00" +@.str1185 = private unnamed_addr constant [32 x i8] c" = getelementptr inbounds %Cmp_\00" +@.str1186 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1187 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str1188 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1189 = private unnamed_addr constant [2 x i8] c"0\00" +@.str1190 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str1191 = private unnamed_addr constant [5 x i8] c"null\00" +@.str1192 = private unnamed_addr constant [9 x i8] c" store \00" +@.str1193 = private unnamed_addr constant [2 x i8] c" \00" +@.str1194 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1195 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1196 = private unnamed_addr constant [3 x i8] c" \00" +@.str1197 = private unnamed_addr constant [32 x i8] c" = getelementptr inbounds %Cmp_\00" +@.str1198 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1199 = private unnamed_addr constant [14 x i8] c", i32 0, i32 \00" +@.str1200 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1201 = private unnamed_addr constant [9 x i8] c" store \00" +@.str1202 = private unnamed_addr constant [2 x i8] c" \00" +@.str1203 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1204 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1205 = private unnamed_addr constant [20 x i8] c"call i32 @L_alloc()\00" +@.str1206 = private unnamed_addr constant [3 x i8] c" \00" +@.str1207 = private unnamed_addr constant [28 x i8] c" = getelementptr inbounds [\00" +@.str1208 = private unnamed_addr constant [34 x i8] c" x i32], ptr @L_kind, i32 0, i32 \00" +@.str1209 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1210 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str1211 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1212 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1213 = private unnamed_addr constant [32 x i8] c" call void @L_free_entity(i32 \00" +@.str1214 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str1215 = private unnamed_addr constant [5 x i8] c"void\00" +@.str1216 = private unnamed_addr constant [17 x i8] c" br label %ret\0A\00" +@.str1217 = private unnamed_addr constant [17 x i8] c"ret:\0A ret void\0A\00" +@.str1218 = private unnamed_addr constant [18 x i8] c"define void @sys_\00" +@.str1219 = private unnamed_addr constant [13 x i8] c"() {\0Aentry:\0A\00" +@.str1220 = private unnamed_addr constant [4 x i8] c"}\0A\0A\00" +@.str1221 = private unnamed_addr constant [18 x i8] c" call void @sys_\00" +@.str1222 = private unnamed_addr constant [4 x i8] c"()\0A\00" +@.str1223 = private unnamed_addr constant [49 x i8] c"define i32 @main(i32 %argc, ptr %argv) {\0Aentry:\0A\00" +@.str1224 = private unnamed_addr constant [32 x i8] c" store i32 %argc, ptr @L_argc\0A\00" +@.str1225 = private unnamed_addr constant [32 x i8] c" store ptr %argv, ptr @L_argv\0A\00" +@.str1226 = private unnamed_addr constant [8 x i8] c"rt_init\00" +@.str1227 = private unnamed_addr constant [27 x i8] c" call void @fn_rt_init()\0A\00" +@.str1228 = private unnamed_addr constant [6 x i8] c"Start\00" +@.str1229 = private unnamed_addr constant [18 x i8] c" br label %loop\0A\00" +@.str1230 = private unnamed_addr constant [7 x i8] c"loop:\0A\00" +@.str1231 = private unnamed_addr constant [25 x i8] c"load i32, ptr @L_running\00" +@.str1232 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str1233 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str1234 = private unnamed_addr constant [11 x i8] c"rt_running\00" +@.str1235 = private unnamed_addr constant [26 x i8] c"call i32 @fn_rt_running()\00" +@.str1236 = private unnamed_addr constant [13 x i8] c"icmp ne i32 \00" +@.str1237 = private unnamed_addr constant [4 x i8] c", 0\00" +@.str1238 = private unnamed_addr constant [8 x i8] c"and i1 \00" +@.str1239 = private unnamed_addr constant [3 x i8] c", \00" +@.str1240 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1241 = private unnamed_addr constant [28 x i8] c", label %body, label %done\0A\00" +@.str1242 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1243 = private unnamed_addr constant [28 x i8] c", label %body, label %done\0A\00" +@.str1244 = private unnamed_addr constant [7 x i8] c"body:\0A\00" +@.str1245 = private unnamed_addr constant [8 x i8] c"rt_poll\00" +@.str1246 = private unnamed_addr constant [23 x i8] c"call i32 @fn_rt_poll()\00" +@.str1247 = private unnamed_addr constant [13 x i8] c" store i32 \00" +@.str1248 = private unnamed_addr constant [14 x i8] c", ptr @L_key\0A\00" +@.str1249 = private unnamed_addr constant [6 x i8] c"Input\00" +@.str1250 = private unnamed_addr constant [12 x i8] c"FixedUpdate\00" +@.str1251 = private unnamed_addr constant [7 x i8] c"Update\00" +@.str1252 = private unnamed_addr constant [11 x i8] c"LateUpdate\00" +@.str1253 = private unnamed_addr constant [7 x i8] c"Render\00" +@.str1254 = private unnamed_addr constant [18 x i8] c" br label %loop\0A\00" +@.str1255 = private unnamed_addr constant [7 x i8] c"done:\0A\00" +@.str1256 = private unnamed_addr constant [12 x i8] c"rt_shutdown\00" +@.str1257 = private unnamed_addr constant [31 x i8] c" call void @fn_rt_shutdown()\0A\00" +@.str1258 = private unnamed_addr constant [15 x i8] c" ret i32 0\0A}\0A\00" +@.str1259 = private unnamed_addr constant [25 x i8] c"call i32 @fn_rt_reg(i32 \00" +@.str1260 = private unnamed_addr constant [2 x i8] c")\00" +@.str1261 = private unnamed_addr constant [6 x i8] c"smend\00" +@.str1262 = private unnamed_addr constant [13 x i8] c"icmp eq i32 \00" +@.str1263 = private unnamed_addr constant [3 x i8] c", \00" +@.str1264 = private unnamed_addr constant [6 x i8] c"sbody\00" +@.str1265 = private unnamed_addr constant [5 x i8] c"sarm\00" +@.str1266 = private unnamed_addr constant [9 x i8] c" br i1 \00" +@.str1267 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1268 = private unnamed_addr constant [10 x i8] c", label %\00" +@.str1269 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1270 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1271 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1272 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1273 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1274 = private unnamed_addr constant [13 x i8] c" br label %\00" +@.str1275 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1276 = private unnamed_addr constant [3 x i8] c":\0A\00" +@.str1277 = private unnamed_addr constant [27 x i8] c"'become' outside a machine\00" +@.str1278 = private unnamed_addr constant [18 x i8] c"become: no state \00" +@.str1279 = private unnamed_addr constant [31 x i8] c" call void @fn_rt_setreg(i32 \00" +@.str1280 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str1281 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str1282 = private unnamed_addr constant [4 x i8] c"%io\00" +@.str1283 = private unnamed_addr constant [3 x i8] c" \00" +@.str1284 = private unnamed_addr constant [14 x i8] c" = call i64 @\00" +@.str1285 = private unnamed_addr constant [6 x i8] c"(ptr \00" +@.str1286 = private unnamed_addr constant [14 x i8] c", i64 1, i64 \00" +@.str1287 = private unnamed_addr constant [11 x i8] c", ptr %f)\0A\00" +@.str1288 = private unnamed_addr constant [8 x i8] c"@L_entc\00" +@.str1289 = private unnamed_addr constant [2 x i8] c"4\00" +@.str1290 = private unnamed_addr constant [9 x i8] c"@L_freen\00" +@.str1291 = private unnamed_addr constant [2 x i8] c"4\00" +@.str1292 = private unnamed_addr constant [21 x i8] c" %nalive = mul i64 \00" +@.str1293 = private unnamed_addr constant [5 x i8] c", 4\0A\00" +@.str1294 = private unnamed_addr constant [9 x i8] c"@L_alive\00" +@.str1295 = private unnamed_addr constant [8 x i8] c"%nalive\00" +@.str1296 = private unnamed_addr constant [12 x i8] c"@L_freelist\00" +@.str1297 = private unnamed_addr constant [8 x i8] c"%nalive\00" +@.str1298 = private unnamed_addr constant [8 x i8] c"@L_kind\00" +@.str1299 = private unnamed_addr constant [8 x i8] c"%nalive\00" +@.str1300 = private unnamed_addr constant [4 x i8] c"@g_\00" +@.str1301 = private unnamed_addr constant [2 x i8] c"4\00" +@.str1302 = private unnamed_addr constant [5 x i8] c"%csz\00" +@.str1303 = private unnamed_addr constant [3 x i8] c" \00" +@.str1304 = private unnamed_addr constant [37 x i8] c" = ptrtoint ptr getelementptr (%Cmp_\00" +@.str1305 = private unnamed_addr constant [17 x i8] c", ptr null, i32 \00" +@.str1306 = private unnamed_addr constant [10 x i8] c") to i64\0A\00" +@.str1307 = private unnamed_addr constant [4 x i8] c"@S_\00" +@.str1308 = private unnamed_addr constant [4 x i8] c"@H_\00" +@.str1309 = private unnamed_addr constant [70 x i8] c"@.sav_path = private unnamed_addr constant [10 x i8] c\22ludic.sav\5C00\22\0A\00" +@.str1310 = private unnamed_addr constant [60 x i8] c"@.sav_wb = private unnamed_addr constant [3 x i8] c\22wb\5C00\22\0A\00" +@.str1311 = private unnamed_addr constant [60 x i8] c"@.sav_rb = private unnamed_addr constant [3 x i8] c\22rb\5C00\22\0A\00" +@.str1312 = private unnamed_addr constant [14 x i8] c"rt_save_state\00" +@.str1313 = private unnamed_addr constant [14 x i8] c"rt_load_state\00" +@.str1314 = private unnamed_addr constant [32 x i8] c"define void @L_save() {\0Aentry:\0A\00" +@.str1315 = private unnamed_addr constant [54 x i8] c" %f = call ptr @fopen(ptr @.sav_path, ptr @.sav_wb)\0A\00" +@.str1316 = private unnamed_addr constant [31 x i8] c" %bad = icmp eq ptr %f, null\0A\00" +@.str1317 = private unnamed_addr constant [41 x i8] c" br i1 %bad, label %out, label %go\0Ago:\0A\00" +@.str1318 = private unnamed_addr constant [7 x i8] c"fwrite\00" +@.str1319 = private unnamed_addr constant [39 x i8] c" call void @fn_rt_save_state(ptr %f)\0A\00" +@.str1320 = private unnamed_addr constant [68 x i8] c" %c = call i32 @fclose(ptr %f)\0A br label %out\0Aout:\0A ret void\0A}\0A\0A\00" +@.str1321 = private unnamed_addr constant [31 x i8] c"define i32 @L_load() {\0Aentry:\0A\00" +@.str1322 = private unnamed_addr constant [54 x i8] c" %f = call ptr @fopen(ptr @.sav_path, ptr @.sav_rb)\0A\00" +@.str1323 = private unnamed_addr constant [31 x i8] c" %bad = icmp eq ptr %f, null\0A\00" +@.str1324 = private unnamed_addr constant [60 x i8] c" br i1 %bad, label %miss, label %go\0Amiss:\0A ret i32 0\0Ago:\0A\00" +@.str1325 = private unnamed_addr constant [6 x i8] c"fread\00" +@.str1326 = private unnamed_addr constant [39 x i8] c" call void @fn_rt_load_state(ptr %f)\0A\00" +@.str1327 = private unnamed_addr constant [48 x i8] c" %c = call i32 @fclose(ptr %f)\0A ret i32 1\0A}\0A\0A\00" +@.str1328 = private unnamed_addr constant [6 x i8] c"panel\00" +@.str1329 = private unnamed_addr constant [4 x i8] c"col\00" +@.str1330 = private unnamed_addr constant [4 x i8] c"row\00" +@.str1331 = private unnamed_addr constant [6 x i8] c"label\00" +@.str1332 = private unnamed_addr constant [7 x i8] c"button\00" +@.str1333 = private unnamed_addr constant [6 x i8] c"image\00" +@.str1334 = private unnamed_addr constant [7 x i8] c"spacer\00" +@.str1335 = private unnamed_addr constant [3 x i8] c"id\00" +@.str1336 = private unnamed_addr constant [31 x i8] c" call void @fn_rt_ui_set(i32 \00" +@.str1337 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str1338 = private unnamed_addr constant [7 x i8] c", i32 \00" +@.str1339 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str1340 = private unnamed_addr constant [2 x i8] c"w\00" +@.str1341 = private unnamed_addr constant [2 x i8] c"h\00" +@.str1342 = private unnamed_addr constant [2 x i8] c"x\00" +@.str1343 = private unnamed_addr constant [2 x i8] c"y\00" +@.str1344 = private unnamed_addr constant [4 x i8] c"pad\00" +@.str1345 = private unnamed_addr constant [4 x i8] c"gap\00" +@.str1346 = private unnamed_addr constant [3 x i8] c"bg\00" +@.str1347 = private unnamed_addr constant [3 x i8] c"fg\00" +@.str1348 = private unnamed_addr constant [7 x i8] c"border\00" +@.str1349 = private unnamed_addr constant [5 x i8] c"grow\00" +@.str1350 = private unnamed_addr constant [5 x i8] c"font\00" +@.str1351 = private unnamed_addr constant [5 x i8] c"size\00" +@.str1352 = private unnamed_addr constant [6 x i8] c"inset\00" +@.str1353 = private unnamed_addr constant [6 x i8] c"focus\00" +@.str1354 = private unnamed_addr constant [33 x i8] c" call void @fn_rt_ui_reset(i32 \00" +@.str1355 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str1356 = private unnamed_addr constant [2 x i8] c"1\00" +@.str1357 = private unnamed_addr constant [3 x i8] c"id\00" +@.str1358 = private unnamed_addr constant [5 x i8] c"text\00" +@.str1359 = private unnamed_addr constant [39 x i8] c" call void @fn_rt_ui_static_text(i32 \00" +@.str1360 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1361 = private unnamed_addr constant [3 x i8] c")\0A\00" +@.str1362 = private unnamed_addr constant [5 x i8] c"skin\00" +@.str1363 = private unnamed_addr constant [6 x i8] c"image\00" +@.str1364 = private unnamed_addr constant [32 x i8] c"call i32 @fn_rt_image_load(ptr \00" +@.str1365 = private unnamed_addr constant [2 x i8] c")\00" +@.str1366 = private unnamed_addr constant [5 x i8] c"skin\00" +@.str1367 = private unnamed_addr constant [6 x i8] c"align\00" +@.str1368 = private unnamed_addr constant [7 x i8] c"center\00" +@.str1369 = private unnamed_addr constant [4 x i8] c"end\00" +@.str1370 = private unnamed_addr constant [2 x i8] c"1\00" +@.str1371 = private unnamed_addr constant [34 x i8] c"define void @ui_build() {\0Aentry:\0A\00" +@.str1372 = private unnamed_addr constant [15 x i8] c" ret void\0A}\0A\0A\00" +@.str1373 = private unnamed_addr constant [3 x i8] c", \00" +@.str1374 = private unnamed_addr constant [7 x i8] c" %arg_\00" +@.str1375 = private unnamed_addr constant [5 x i8] c"void\00" +@.str1376 = private unnamed_addr constant [20 x i8] c" %retval = alloca \00" +@.str1377 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1378 = private unnamed_addr constant [9 x i8] c" store \00" +@.str1379 = private unnamed_addr constant [7 x i8] c" %arg_\00" +@.str1380 = private unnamed_addr constant [7 x i8] c", ptr \00" +@.str1381 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1382 = private unnamed_addr constant [17 x i8] c" br label %ret\0A\00" +@.str1383 = private unnamed_addr constant [6 x i8] c"ret:\0A\00" +@.str1384 = private unnamed_addr constant [5 x i8] c"void\00" +@.str1385 = private unnamed_addr constant [12 x i8] c" ret void\0A\00" +@.str1386 = private unnamed_addr constant [6 x i8] c"load \00" +@.str1387 = private unnamed_addr constant [14 x i8] c", ptr %retval\00" +@.str1388 = private unnamed_addr constant [7 x i8] c" ret \00" +@.str1389 = private unnamed_addr constant [2 x i8] c" \00" +@.str1390 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1391 = private unnamed_addr constant [8 x i8] c"define \00" +@.str1392 = private unnamed_addr constant [6 x i8] c" @fn_\00" +@.str1393 = private unnamed_addr constant [2 x i8] c"(\00" +@.str1394 = private unnamed_addr constant [12 x i8] c") {\0Aentry:\0A\00" +@.str1395 = private unnamed_addr constant [4 x i8] c"}\0A\0A\00" +@.str1396 = private unnamed_addr constant [4 x i8] c"int\00" +@.str1397 = private unnamed_addr constant [24 x i8] c" %retval = alloca i32\0A\00" +@.str1398 = private unnamed_addr constant [32 x i8] c" store i32 %argc, ptr @L_argc\0A\00" +@.str1399 = private unnamed_addr constant [32 x i8] c" store ptr %argv, ptr @L_argv\0A\00" +@.str1400 = private unnamed_addr constant [28 x i8] c" store i32 0, ptr %retval\0A\00" +@.str1401 = private unnamed_addr constant [17 x i8] c" br label %ret\0A\00" +@.str1402 = private unnamed_addr constant [6 x i8] c"ret:\0A\00" +@.str1403 = private unnamed_addr constant [22 x i8] c"load i32, ptr %retval\00" +@.str1404 = private unnamed_addr constant [11 x i8] c" ret i32 \00" +@.str1405 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1406 = private unnamed_addr constant [49 x i8] c"define i32 @main(i32 %argc, ptr %argv) {\0Aentry:\0A\00" +@.str1407 = private unnamed_addr constant [3 x i8] c"}\0A\00" +@.str1408 = private unnamed_addr constant [3 x i8] c"wb\00" +@.str1409 = private unnamed_addr constant [7 x i8] c".ludic\00" +@.str1410 = private unnamed_addr constant [2 x i8] c"/\00" +@.str1411 = private unnamed_addr constant [6 x i8] c"ludic\00" +@.str1412 = private unnamed_addr constant [11 x i8] c"--windowed\00" +@.str1413 = private unnamed_addr constant [11 x i8] c"--headless\00" +@.str1414 = private unnamed_addr constant [12 x i8] c"--emit-llvm\00" +@.str1415 = private unnamed_addr constant [6 x i8] c"--fmt\00" +@.str1416 = private unnamed_addr constant [13 x i8] c"--save-temps\00" +@.str1417 = private unnamed_addr constant [6 x i8] c"--run\00" +@.str1418 = private unnamed_addr constant [3 x i8] c"-o\00" +@.str1419 = private unnamed_addr constant [31 x i8] c"ludicc: ignoring unknown flag \00" +@.str1420 = private unnamed_addr constant [2 x i8] c"\0A\00" +@.str1421 = private unnamed_addr constant [90 x i8] c"usage: ludicc [-o out] [--windowed|--headless] [--emit-llvm] [--save-temps]\0A\00" +@.str1422 = private unnamed_addr constant [27 x i8] c"ludicc: cannot open input\0A\00" +@.str1423 = private unnamed_addr constant [16 x i8] c"/tmp/ludic-run-\00" +@.str1424 = private unnamed_addr constant [10 x i8] c"mkdir -p \00" +@.str1425 = private unnamed_addr constant [4 x i8] c".ll\00" +@.str1426 = private unnamed_addr constant [25 x i8] c"ludicc: cannot write IR\0A\00" +@.str1427 = private unnamed_addr constant [9 x i8] c"LUDIC_CC\00" +@.str1428 = private unnamed_addr constant [6 x i8] c"clang\00" +@.str1429 = private unnamed_addr constant [11 x i8] c"LUDIC_HOME\00" +@.str1430 = private unnamed_addr constant [27 x i8] c" -O2 -Wno-override-module \00" +@.str1431 = private unnamed_addr constant [24 x i8] c"runtime/native/cocoa.ll\00" +@.str1432 = private unnamed_addr constant [2 x i8] c" \00" +@.str1433 = private unnamed_addr constant [42 x i8] c" -framework Cocoa -Wl,-rpath,@loader_path\00" +@.str1434 = private unnamed_addr constant [5 x i8] c" -o \00" +@.str1435 = private unnamed_addr constant [7 x i8] c"rm -f \00" +@.str1436 = private unnamed_addr constant [21 x i8] c"ludicc: link failed\0A\00" +define i32 @fn_streq(ptr %arg_a, ptr %arg_b) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + %t9 = alloca i32 + %t15 = alloca i32 + store ptr %arg_a, ptr %t0 + store ptr %arg_b, ptr %t1 + store i32 0, ptr %t2 + br label %wcond0 +wcond0: + %t3 = icmp ne i32 1, 0 + br i1 %t3, label %wbody1, label %wend2 +wbody1: + %t4 = load ptr, ptr %t0 + %t5 = load i32, ptr %t2 + %t6 = getelementptr inbounds i8, ptr %t4, i32 %t5 + %t7 = load i8, ptr %t6 + %t8 = zext i8 %t7 to i32 + store i32 %t8, ptr %t9 + %t10 = load ptr, ptr %t1 + %t11 = load i32, ptr %t2 + %t12 = getelementptr inbounds i8, ptr %t10, i32 %t11 + %t13 = load i8, ptr %t12 + %t14 = zext i8 %t13 to i32 + store i32 %t14, ptr %t15 + %t16 = load i32, ptr %t9 + %t17 = load i32, ptr %t15 + %t18 = icmp ne i32 %t16, %t17 + %t19 = zext i1 %t18 to i32 + %t20 = icmp ne i32 %t19, 0 + br i1 %t20, label %then3, label %ifend5 +then3: + store i32 0, ptr %retval + br label %ret +ifend5: + %t21 = load i32, ptr %t9 + %t22 = icmp eq i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + %t24 = icmp ne i32 %t23, 0 + br i1 %t24, label %then6, label %ifend8 +then6: + store i32 1, ptr %retval + br label %ret +ifend8: + %t25 = load i32, ptr %t2 + %t26 = add i32 %t25, 1 + store i32 %t26, ptr %t2 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t27 = load i32, ptr %retval + ret i32 %t27 +} + +define i32 @fn_slen(ptr %arg_s) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_s, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load ptr, ptr %t0 + %t3 = load i32, ptr %t1 + %t4 = getelementptr inbounds i8, ptr %t2, i32 %t3 + %t5 = load i8, ptr %t4 + %t6 = zext i8 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + %t8 = zext i1 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %wbody1, label %wend2 +wbody1: + %t10 = load i32, ptr %t1 + %t11 = add i32 %t10, 1 + store i32 %t11, ptr %t1 + br label %wcond0 +wend2: + %t12 = load i32, ptr %t1 + store i32 %t12, ptr %retval + br label %ret +ret: + %t13 = load i32, ptr %retval + ret i32 %t13 +} + +define ptr @fn_substr(ptr %arg_src, i32 %arg_start, i32 %arg_n) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t7 = alloca ptr + %t8 = alloca i32 + store ptr %arg_src, ptr %t0 + store i32 %arg_start, ptr %t1 + store i32 %arg_n, ptr %t2 + %t3 = load i32, ptr %t2 + %t4 = add i32 %t3, 1 + %t5 = zext i32 %t4 to i64 + %t6 = call ptr @malloc(i64 %t5) + store ptr %t6, ptr %t7 + store i32 0, ptr %t8 + br label %wcond0 +wcond0: + %t9 = load i32, ptr %t8 + %t10 = load i32, ptr %t2 + %t11 = icmp slt i32 %t9, %t10 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %wbody1, label %wend2 +wbody1: + %t14 = load ptr, ptr %t7 + %t15 = load i32, ptr %t8 + %t16 = load ptr, ptr %t0 + %t17 = load i32, ptr %t1 + %t18 = load i32, ptr %t8 + %t19 = add i32 %t17, %t18 + %t20 = getelementptr inbounds i8, ptr %t16, i32 %t19 + %t21 = load i8, ptr %t20 + %t22 = zext i8 %t21 to i32 + %t23 = getelementptr inbounds i8, ptr %t14, i32 %t15 + %t24 = trunc i32 %t22 to i8 + store i8 %t24, ptr %t23 + %t25 = load i32, ptr %t8 + %t26 = add i32 %t25, 1 + store i32 %t26, ptr %t8 + br label %wcond0 +wend2: + %t27 = load ptr, ptr %t7 + %t28 = load i32, ptr %t2 + %t29 = getelementptr inbounds i8, ptr %t27, i32 %t28 + %t30 = trunc i32 0 to i8 + store i8 %t30, ptr %t29 + %t31 = load ptr, ptr %t7 + store ptr %t31, ptr %retval + br label %ret +ret: + %t32 = load ptr, ptr %retval + ret ptr %t32 +} + +define i32 @fn_char_is_digit(i32 %arg_c) { +entry: + %retval = alloca i32 + %t0 = alloca i32 + %t1 = alloca i32 + store i32 %arg_c, ptr %t0 + %t2 = load i32, ptr %t0 + %t3 = icmp sge i32 %t2, 48 + %t4 = zext i1 %t3 to i32 + %t5 = icmp ne i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %t1 + br i1 %t5, label %sc0, label %scend1 +sc0: + %t7 = load i32, ptr %t0 + %t8 = icmp sle i32 %t7, 57 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + store i32 %t11, ptr %t1 + br label %scend1 +scend1: + %t12 = load i32, ptr %t1 + store i32 %t12, ptr %retval + br label %ret +ret: + %t13 = load i32, ptr %retval + ret i32 %t13 +} + +define i32 @fn_char_is_alpha(i32 %arg_c) { +entry: + %retval = alloca i32 + %t0 = alloca i32 + %t1 = alloca i32 + %t14 = alloca i32 + store i32 %arg_c, ptr %t0 + %t2 = load i32, ptr %t0 + %t3 = icmp sge i32 %t2, 65 + %t4 = zext i1 %t3 to i32 + %t5 = icmp ne i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %t1 + br i1 %t5, label %sc0, label %scend1 +sc0: + %t7 = load i32, ptr %t0 + %t8 = icmp sle i32 %t7, 90 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + store i32 %t11, ptr %t1 + br label %scend1 +scend1: + %t12 = load i32, ptr %t1 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then2, label %ifend4 +then2: + store i32 1, ptr %retval + br label %ret +ifend4: + %t15 = load i32, ptr %t0 + %t16 = icmp sge i32 %t15, 97 + %t17 = zext i1 %t16 to i32 + %t18 = icmp ne i32 %t17, 0 + %t19 = zext i1 %t18 to i32 + store i32 %t19, ptr %t14 + br i1 %t18, label %sc5, label %scend6 +sc5: + %t20 = load i32, ptr %t0 + %t21 = icmp sle i32 %t20, 122 + %t22 = zext i1 %t21 to i32 + %t23 = icmp ne i32 %t22, 0 + %t24 = zext i1 %t23 to i32 + store i32 %t24, ptr %t14 + br label %scend6 +scend6: + %t25 = load i32, ptr %t14 + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %then7, label %ifend9 +then7: + store i32 1, ptr %retval + br label %ret +ifend9: + %t27 = load i32, ptr %t0 + %t28 = icmp eq i32 %t27, 95 + %t29 = zext i1 %t28 to i32 + store i32 %t29, ptr %retval + br label %ret +ret: + %t30 = load i32, ptr %retval + ret i32 %t30 +} + +define i32 @fn_char_is_alnum(i32 %arg_c) { +entry: + %retval = alloca i32 + %t0 = alloca i32 + %t1 = alloca i32 + store i32 %arg_c, ptr %t0 + %t2 = load i32, ptr %t0 + %t3 = call i32 @fn_char_is_alpha(i32 %t2) + %t4 = icmp ne i32 %t3, 0 + %t5 = zext i1 %t4 to i32 + store i32 %t5, ptr %t1 + br i1 %t4, label %scend1, label %sc0 +sc0: + %t6 = load i32, ptr %t0 + %t7 = call i32 @fn_char_is_digit(i32 %t6) + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t1 + br label %scend1 +scend1: + %t10 = load i32, ptr %t1 + store i32 %t10, ptr %retval + br label %ret +ret: + %t11 = load i32, ptr %retval + ret i32 %t11 +} + +define ptr @fn_itoa(i32 %arg_v) { +entry: + %retval = alloca ptr + %t0 = alloca i32 + %t7 = alloca ptr + %t15 = alloca i32 + %t17 = alloca i32 + %t26 = alloca ptr + %t27 = alloca i32 + %t44 = alloca i32 + %t53 = alloca ptr + %t54 = alloca i32 + %t60 = alloca i32 + store i32 %arg_v, ptr %t0 + %t1 = load i32, ptr %t0 + %t2 = icmp eq i32 %t1, 0 + %t3 = zext i1 %t2 to i32 + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + %t5 = zext i32 2 to i64 + %t6 = call ptr @malloc(i64 %t5) + store ptr %t6, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds i8, ptr %t8, i32 0 + %t10 = trunc i32 48 to i8 + store i8 %t10, ptr %t9 + %t11 = load ptr, ptr %t7 + %t12 = getelementptr inbounds i8, ptr %t11, i32 1 + %t13 = trunc i32 0 to i8 + store i8 %t13, ptr %t12 + %t14 = load ptr, ptr %t7 + store ptr %t14, ptr %retval + br label %ret +ifend2: + store i32 0, ptr %t15 + %t16 = load i32, ptr %t0 + store i32 %t16, ptr %t17 + %t18 = load i32, ptr %t17 + %t19 = icmp slt i32 %t18, 0 + %t20 = zext i1 %t19 to i32 + %t21 = icmp ne i32 %t20, 0 + br i1 %t21, label %then3, label %ifend5 +then3: + store i32 1, ptr %t15 + %t22 = load i32, ptr %t17 + %t23 = sub i32 0, %t22 + store i32 %t23, ptr %t17 + br label %ifend5 +ifend5: + %t24 = zext i32 16 to i64 + %t25 = call ptr @malloc(i64 %t24) + store ptr %t25, ptr %t26 + store i32 0, ptr %t27 + br label %wcond6 +wcond6: + %t28 = load i32, ptr %t17 + %t29 = icmp sgt i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + %t31 = icmp ne i32 %t30, 0 + br i1 %t31, label %wbody7, label %wend8 +wbody7: + %t32 = load ptr, ptr %t26 + %t33 = load i32, ptr %t27 + %t34 = load i32, ptr %t17 + %t35 = srem i32 %t34, 10 + %t36 = add i32 48, %t35 + %t37 = getelementptr inbounds i8, ptr %t32, i32 %t33 + %t38 = trunc i32 %t36 to i8 + store i8 %t38, ptr %t37 + %t39 = load i32, ptr %t17 + %t40 = sdiv i32 %t39, 10 + store i32 %t40, ptr %t17 + %t41 = load i32, ptr %t27 + %t42 = add i32 %t41, 1 + store i32 %t42, ptr %t27 + br label %wcond6 +wend8: + %t43 = load i32, ptr %t27 + store i32 %t43, ptr %t44 + %t45 = load i32, ptr %t15 + %t46 = icmp ne i32 %t45, 0 + br i1 %t46, label %then9, label %ifend11 +then9: + %t47 = load i32, ptr %t44 + %t48 = add i32 %t47, 1 + store i32 %t48, ptr %t44 + br label %ifend11 +ifend11: + %t49 = load i32, ptr %t44 + %t50 = add i32 %t49, 1 + %t51 = zext i32 %t50 to i64 + %t52 = call ptr @malloc(i64 %t51) + store ptr %t52, ptr %t53 + store i32 0, ptr %t54 + %t55 = load i32, ptr %t15 + %t56 = icmp ne i32 %t55, 0 + br i1 %t56, label %then12, label %ifend14 +then12: + %t57 = load ptr, ptr %t53 + %t58 = getelementptr inbounds i8, ptr %t57, i32 0 + %t59 = trunc i32 45 to i8 + store i8 %t59, ptr %t58 + store i32 1, ptr %t54 + br label %ifend14 +ifend14: + store i32 0, ptr %t60 + br label %wcond15 +wcond15: + %t61 = load i32, ptr %t60 + %t62 = load i32, ptr %t27 + %t63 = icmp slt i32 %t61, %t62 + %t64 = zext i1 %t63 to i32 + %t65 = icmp ne i32 %t64, 0 + br i1 %t65, label %wbody16, label %wend17 +wbody16: + %t66 = load ptr, ptr %t53 + %t67 = load i32, ptr %t54 + %t68 = load i32, ptr %t60 + %t69 = add i32 %t67, %t68 + %t70 = load ptr, ptr %t26 + %t71 = load i32, ptr %t27 + %t72 = sub i32 %t71, 1 + %t73 = load i32, ptr %t60 + %t74 = sub i32 %t72, %t73 + %t75 = getelementptr inbounds i8, ptr %t70, i32 %t74 + %t76 = load i8, ptr %t75 + %t77 = zext i8 %t76 to i32 + %t78 = getelementptr inbounds i8, ptr %t66, i32 %t69 + %t79 = trunc i32 %t77 to i8 + store i8 %t79, ptr %t78 + %t80 = load i32, ptr %t60 + %t81 = add i32 %t80, 1 + store i32 %t81, ptr %t60 + br label %wcond15 +wend17: + %t82 = load ptr, ptr %t53 + %t83 = load i32, ptr %t44 + %t84 = getelementptr inbounds i8, ptr %t82, i32 %t83 + %t85 = trunc i32 0 to i8 + store i8 %t85, ptr %t84 + %t86 = load ptr, ptr %t53 + store ptr %t86, ptr %retval + br label %ret +ret: + %t87 = load ptr, ptr %retval + ret ptr %t87 +} + +define ptr @fn_buf_new() { +entry: + %retval = alloca ptr + %t6 = alloca ptr + %t0 = getelementptr %Str_Buf, ptr null, i32 1 + %t1 = ptrtoint ptr %t0 to i64 + %t2 = call ptr @malloc(i64 %t1) + %t3 = getelementptr inbounds %Str_Buf, ptr %t2, i32 0, i32 0 + store ptr null, ptr %t3 + %t4 = getelementptr inbounds %Str_Buf, ptr %t2, i32 0, i32 1 + store i32 0, ptr %t4 + %t5 = getelementptr inbounds %Str_Buf, ptr %t2, i32 0, i32 2 + store i32 0, ptr %t5 + store ptr %t2, ptr %t6 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %Str_Buf, ptr %t7, i32 0, i32 2 + store i32 256, ptr %t8 + %t9 = load ptr, ptr %t6 + %t10 = getelementptr inbounds %Str_Buf, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t6 + %t12 = getelementptr inbounds %Str_Buf, ptr %t11, i32 0, i32 2 + %t13 = load i32, ptr %t12 + %t14 = zext i32 %t13 to i64 + %t15 = call ptr @malloc(i64 %t14) + store ptr %t15, ptr %t10 + %t16 = load ptr, ptr %t6 + %t17 = getelementptr inbounds %Str_Buf, ptr %t16, i32 0, i32 1 + store i32 0, ptr %t17 + %t18 = load ptr, ptr %t6 + store ptr %t18, ptr %retval + br label %ret +ret: + %t19 = load ptr, ptr %retval + ret ptr %t19 +} + +define void @fn_buf_ensure(ptr %arg_b, i32 %arg_extra) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_b, ptr %t0 + store i32 %arg_extra, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = getelementptr inbounds %Str_Buf, ptr %t2, i32 0, i32 1 + %t4 = load i32, ptr %t3 + %t5 = load i32, ptr %t1 + %t6 = add i32 %t4, %t5 + %t7 = add i32 %t6, 1 + %t8 = load ptr, ptr %t0 + %t9 = getelementptr inbounds %Str_Buf, ptr %t8, i32 0, i32 2 + %t10 = load i32, ptr %t9 + %t11 = icmp sle i32 %t7, %t10 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then0, label %ifend2 +then0: + br label %ret +ifend2: + br label %wcond3 +wcond3: + %t14 = load ptr, ptr %t0 + %t15 = getelementptr inbounds %Str_Buf, ptr %t14, i32 0, i32 1 + %t16 = load i32, ptr %t15 + %t17 = load i32, ptr %t1 + %t18 = add i32 %t16, %t17 + %t19 = add i32 %t18, 1 + %t20 = load ptr, ptr %t0 + %t21 = getelementptr inbounds %Str_Buf, ptr %t20, i32 0, i32 2 + %t22 = load i32, ptr %t21 + %t23 = icmp sgt i32 %t19, %t22 + %t24 = zext i1 %t23 to i32 + %t25 = icmp ne i32 %t24, 0 + br i1 %t25, label %wbody4, label %wend5 +wbody4: + %t26 = load ptr, ptr %t0 + %t27 = getelementptr inbounds %Str_Buf, ptr %t26, i32 0, i32 2 + %t28 = load ptr, ptr %t0 + %t29 = getelementptr inbounds %Str_Buf, ptr %t28, i32 0, i32 2 + %t30 = load i32, ptr %t29 + %t31 = mul i32 %t30, 2 + store i32 %t31, ptr %t27 + br label %wcond3 +wend5: + %t32 = load ptr, ptr %t0 + %t33 = getelementptr inbounds %Str_Buf, ptr %t32, i32 0, i32 0 + %t34 = load ptr, ptr %t0 + %t35 = getelementptr inbounds %Str_Buf, ptr %t34, i32 0, i32 0 + %t36 = load ptr, ptr %t35 + %t37 = load ptr, ptr %t0 + %t38 = getelementptr inbounds %Str_Buf, ptr %t37, i32 0, i32 2 + %t39 = load i32, ptr %t38 + %t40 = zext i32 %t39 to i64 + %t41 = call ptr @realloc(ptr %t36, i64 %t40) + store ptr %t41, ptr %t33 + br label %ret +ret: + ret void +} + +define void @fn_buf_putc(ptr %arg_b, i32 %arg_c) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_b, ptr %t0 + store i32 %arg_c, ptr %t1 + %t2 = load ptr, ptr %t0 + call void @fn_buf_ensure(ptr %t2, i32 1) + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Buf, ptr %t3, i32 0, i32 0 + %t5 = load ptr, ptr %t4 + %t6 = load ptr, ptr %t0 + %t7 = getelementptr inbounds %Str_Buf, ptr %t6, i32 0, i32 1 + %t8 = load i32, ptr %t7 + %t9 = load i32, ptr %t1 + %t10 = getelementptr inbounds i8, ptr %t5, i32 %t8 + %t11 = trunc i32 %t9 to i8 + store i8 %t11, ptr %t10 + %t12 = load ptr, ptr %t0 + %t13 = getelementptr inbounds %Str_Buf, ptr %t12, i32 0, i32 1 + %t14 = load ptr, ptr %t0 + %t15 = getelementptr inbounds %Str_Buf, ptr %t14, i32 0, i32 1 + %t16 = load i32, ptr %t15 + %t17 = add i32 %t16, 1 + store i32 %t17, ptr %t13 + br label %ret +ret: + ret void +} + +define void @fn_buf_puts(ptr %arg_b, ptr %arg_s) { +entry: + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + store ptr %arg_b, ptr %t0 + store ptr %arg_s, ptr %t1 + store i32 0, ptr %t2 + br label %wcond0 +wcond0: + %t3 = load ptr, ptr %t1 + %t4 = load i32, ptr %t2 + %t5 = getelementptr inbounds i8, ptr %t3, i32 %t4 + %t6 = load i8, ptr %t5 + %t7 = zext i8 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t11 = load ptr, ptr %t0 + %t12 = load ptr, ptr %t1 + %t13 = load i32, ptr %t2 + %t14 = getelementptr inbounds i8, ptr %t12, i32 %t13 + %t15 = load i8, ptr %t14 + %t16 = zext i8 %t15 to i32 + call void @fn_buf_putc(ptr %t11, i32 %t16) + %t17 = load i32, ptr %t2 + %t18 = add i32 %t17, 1 + store i32 %t18, ptr %t2 + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define void @fn_buf_puti(ptr %arg_b, i32 %arg_n) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_b, ptr %t0 + store i32 %arg_n, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = load i32, ptr %t1 + %t4 = call ptr @fn_itoa(i32 %t3) + call void @fn_buf_puts(ptr %t2, ptr %t4) + br label %ret +ret: + ret void +} + +define ptr @fn_buf_str(ptr %arg_b) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + store ptr %arg_b, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Buf, ptr %t1, i32 0, i32 0 + %t3 = load ptr, ptr %t2 + %t4 = load ptr, ptr %t0 + %t5 = getelementptr inbounds %Str_Buf, ptr %t4, i32 0, i32 1 + %t6 = load i32, ptr %t5 + %t7 = getelementptr inbounds i8, ptr %t3, i32 %t6 + %t8 = trunc i32 0 to i8 + store i8 %t8, ptr %t7 + %t9 = load ptr, ptr %t0 + %t10 = getelementptr inbounds %Str_Buf, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + store ptr %t11, ptr %retval + br label %ret +ret: + %t12 = load ptr, ptr %retval + ret ptr %t12 +} + +define ptr @fn_read_file(ptr %arg_path) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t3 = alloca ptr + %t14 = alloca i32 + %t22 = alloca ptr + store ptr %arg_path, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call ptr @fopen(ptr %t1, ptr @.str0) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = icmp eq ptr %t4, null + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + store ptr null, ptr %retval + br label %ret +ifend2: + %t8 = load ptr, ptr %t3 + %t9 = sext i32 0 to i64 + %t10 = call i32 @fseek(ptr %t8, i64 %t9, i32 2) + %t11 = load ptr, ptr %t3 + %t12 = call i64 @ftell(ptr %t11) + %t13 = trunc i64 %t12 to i32 + store i32 %t13, ptr %t14 + %t15 = load ptr, ptr %t3 + %t16 = sext i32 0 to i64 + %t17 = call i32 @fseek(ptr %t15, i64 %t16, i32 0) + %t18 = load i32, ptr %t14 + %t19 = add i32 %t18, 1 + %t20 = zext i32 %t19 to i64 + %t21 = call ptr @malloc(i64 %t20) + store ptr %t21, ptr %t22 + %t23 = load ptr, ptr %t3 + %t24 = load ptr, ptr %t22 + %t25 = load i32, ptr %t14 + %t26 = zext i32 %t25 to i64 + %t27 = call i64 @fread(ptr %t24, i64 1, i64 %t26, ptr %t23) + %t28 = trunc i64 %t27 to i32 + %t29 = load ptr, ptr %t22 + %t30 = load i32, ptr %t14 + %t31 = getelementptr inbounds i8, ptr %t29, i32 %t30 + %t32 = trunc i32 0 to i8 + store i8 %t32, ptr %t31 + %t33 = load ptr, ptr %t3 + call i32 @fclose(ptr %t33) + %t34 = load ptr, ptr %t22 + store ptr %t34, ptr %retval + br label %ret +ret: + %t35 = load ptr, ptr %retval + ret ptr %t35 +} + +define i32 @fn_cstr_len(ptr %arg_s) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_s, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load ptr, ptr %t0 + %t3 = load i32, ptr %t1 + %t4 = getelementptr inbounds i8, ptr %t2, i32 %t3 + %t5 = load i8, ptr %t4 + %t6 = zext i8 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + %t8 = zext i1 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %wbody1, label %wend2 +wbody1: + %t10 = load i32, ptr %t1 + %t11 = add i32 %t10, 1 + store i32 %t11, ptr %t1 + br label %wcond0 +wend2: + %t12 = load i32, ptr %t1 + store i32 %t12, ptr %retval + br label %ret +ret: + %t13 = load i32, ptr %retval + ret i32 %t13 +} + +define ptr @fn_node(i32 %arg_kind) { +entry: + %retval = alloca ptr + %t0 = alloca i32 + %t13 = alloca ptr + store i32 %arg_kind, ptr %t0 + %t1 = getelementptr %Str_Node, ptr null, i32 1 + %t2 = ptrtoint ptr %t1 to i64 + %t3 = call ptr @malloc(i64 %t2) + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 0 + store i32 0, ptr %t4 + %t5 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 1 + store ptr null, ptr %t5 + %t6 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 2 + store i32 0, ptr %t6 + %t7 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 3 + store ptr null, ptr %t7 + %t8 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 4 + store ptr null, ptr %t8 + %t9 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 5 + store ptr null, ptr %t9 + %t10 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 6 + store ptr null, ptr %t10 + %t11 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 7 + store ptr null, ptr %t11 + %t12 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 8 + store i32 0, ptr %t12 + store ptr %t3, ptr %t13 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %Str_Node, ptr %t14, i32 0, i32 0 + %t16 = load i32, ptr %t0 + store i32 %t16, ptr %t15 + %t17 = load ptr, ptr %t13 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 7 + %t19 = getelementptr %LSlice, ptr null, i32 1 + %t20 = ptrtoint ptr %t19 to i64 + %t21 = call ptr @malloc(i64 %t20) + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 0 + store ptr null, ptr %t22 + %t23 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 1 + store i32 0, ptr %t23 + %t24 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 2 + store i32 0, ptr %t24 + store ptr %t21, ptr %t18 + %t25 = load ptr, ptr %t13 + store ptr %t25, ptr %retval + br label %ret +ret: + %t26 = load ptr, ptr %retval + ret ptr %t26 +} + +define void @fn_tok_push(i32 %arg_kind, ptr %arg_text, i32 %arg_ival, i32 %arg_line) { +entry: + %t0 = alloca i32 + %t1 = alloca ptr + %t2 = alloca i32 + %t3 = alloca i32 + %t11 = alloca ptr + store i32 %arg_kind, ptr %t0 + store ptr %arg_text, ptr %t1 + store i32 %arg_ival, ptr %t2 + store i32 %arg_line, ptr %t3 + %t4 = getelementptr %Str_Tok, ptr null, i32 1 + %t5 = ptrtoint ptr %t4 to i64 + %t6 = call ptr @malloc(i64 %t5) + %t7 = getelementptr inbounds %Str_Tok, ptr %t6, i32 0, i32 0 + store i32 0, ptr %t7 + %t8 = getelementptr inbounds %Str_Tok, ptr %t6, i32 0, i32 1 + store ptr null, ptr %t8 + %t9 = getelementptr inbounds %Str_Tok, ptr %t6, i32 0, i32 2 + store i32 0, ptr %t9 + %t10 = getelementptr inbounds %Str_Tok, ptr %t6, i32 0, i32 3 + store i32 0, ptr %t10 + store ptr %t6, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Tok, ptr %t12, i32 0, i32 0 + %t14 = load i32, ptr %t0 + store i32 %t14, ptr %t13 + %t15 = load ptr, ptr %t11 + %t16 = getelementptr inbounds %Str_Tok, ptr %t15, i32 0, i32 1 + %t17 = load ptr, ptr %t1 + store ptr %t17, ptr %t16 + %t18 = load ptr, ptr %t11 + %t19 = getelementptr inbounds %Str_Tok, ptr %t18, i32 0, i32 2 + %t20 = load i32, ptr %t2 + store i32 %t20, ptr %t19 + %t21 = load ptr, ptr %t11 + %t22 = getelementptr inbounds %Str_Tok, ptr %t21, i32 0, i32 3 + %t23 = load i32, ptr %t3 + store i32 %t23, ptr %t22 + %t24 = load ptr, ptr @g_toks + %t25 = getelementptr inbounds %LSlice, ptr %t24, i32 0, i32 1 + %t26 = getelementptr inbounds %LSlice, ptr %t24, i32 0, i32 2 + %t27 = getelementptr inbounds %LSlice, ptr %t24, i32 0, i32 0 + %t28 = load i32, ptr %t25 + %t29 = load i32, ptr %t26 + %t30 = icmp sge i32 %t28, %t29 + br i1 %t30, label %grow0, label %put1 +grow0: + %t31 = mul i32 %t29, 2 + %t32 = icmp eq i32 %t29, 0 + %t33 = select i1 %t32, i32 8, i32 %t31 + %t34 = getelementptr ptr, ptr null, i32 1 + %t35 = ptrtoint ptr %t34 to i64 + %t36 = zext i32 %t33 to i64 + %t37 = mul i64 %t36, %t35 + %t38 = load ptr, ptr %t27 + %t39 = call ptr @realloc(ptr %t38, i64 %t37) + store ptr %t39, ptr %t27 + store i32 %t33, ptr %t26 + br label %put1 +put1: + %t40 = load ptr, ptr %t11 + %t41 = load ptr, ptr %t27 + %t42 = getelementptr inbounds ptr, ptr %t41, i32 %t28 + store ptr %t40, ptr %t42 + %t43 = add i32 %t28, 1 + store i32 %t43, ptr %t25 + br label %ret +ret: + ret void +} + +define i32 @fn_two_at(ptr %arg_src, i32 %arg_i, i32 %arg_a, i32 %arg_b) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t3 = alloca i32 + %t4 = alloca i32 + store ptr %arg_src, ptr %t0 + store i32 %arg_i, ptr %t1 + store i32 %arg_a, ptr %t2 + store i32 %arg_b, ptr %t3 + %t5 = load ptr, ptr %t0 + %t6 = load i32, ptr %t1 + %t7 = getelementptr inbounds i8, ptr %t5, i32 %t6 + %t8 = load i8, ptr %t7 + %t9 = zext i8 %t8 to i32 + %t10 = load i32, ptr %t2 + %t11 = icmp eq i32 %t9, %t10 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + %t14 = zext i1 %t13 to i32 + store i32 %t14, ptr %t4 + br i1 %t13, label %sc0, label %scend1 +sc0: + %t15 = load ptr, ptr %t0 + %t16 = load i32, ptr %t1 + %t17 = add i32 %t16, 1 + %t18 = getelementptr inbounds i8, ptr %t15, i32 %t17 + %t19 = load i8, ptr %t18 + %t20 = zext i8 %t19 to i32 + %t21 = load i32, ptr %t3 + %t22 = icmp eq i32 %t20, %t21 + %t23 = zext i1 %t22 to i32 + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t4 + br label %scend1 +scend1: + %t26 = load i32, ptr %t4 + store i32 %t26, ptr %retval + br label %ret +ret: + %t27 = load i32, ptr %retval + ret i32 %t27 +} + +define i32 @fn_is_op1(i32 %arg_c) { +entry: + %retval = alloca i32 + %t0 = alloca i32 + %t1 = alloca i32 + %t2 = alloca i32 + %t3 = alloca i32 + %t4 = alloca i32 + %t41 = alloca i32 + %t42 = alloca i32 + %t63 = alloca i32 + %t64 = alloca i32 + %t65 = alloca i32 + %t94 = alloca i32 + %t95 = alloca i32 + %t96 = alloca i32 + %t97 = alloca i32 + %t134 = alloca i32 + store i32 %arg_c, ptr %t0 + %t5 = load i32, ptr %t0 + %t6 = icmp eq i32 %t5, 43 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t4 + br i1 %t8, label %scend1, label %sc0 +sc0: + %t10 = load i32, ptr %t0 + %t11 = icmp eq i32 %t10, 45 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + %t14 = zext i1 %t13 to i32 + store i32 %t14, ptr %t4 + br label %scend1 +scend1: + %t15 = load i32, ptr %t4 + %t16 = icmp ne i32 %t15, 0 + %t17 = zext i1 %t16 to i32 + store i32 %t17, ptr %t3 + br i1 %t16, label %scend3, label %sc2 +sc2: + %t18 = load i32, ptr %t0 + %t19 = icmp eq i32 %t18, 42 + %t20 = zext i1 %t19 to i32 + %t21 = icmp ne i32 %t20, 0 + %t22 = zext i1 %t21 to i32 + store i32 %t22, ptr %t3 + br label %scend3 +scend3: + %t23 = load i32, ptr %t3 + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t2 + br i1 %t24, label %scend5, label %sc4 +sc4: + %t26 = load i32, ptr %t0 + %t27 = icmp eq i32 %t26, 47 + %t28 = zext i1 %t27 to i32 + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t2 + br label %scend5 +scend5: + %t31 = load i32, ptr %t2 + %t32 = icmp ne i32 %t31, 0 + %t33 = zext i1 %t32 to i32 + store i32 %t33, ptr %t1 + br i1 %t32, label %scend7, label %sc6 +sc6: + %t34 = load i32, ptr %t0 + %t35 = icmp eq i32 %t34, 37 + %t36 = zext i1 %t35 to i32 + %t37 = icmp ne i32 %t36, 0 + %t38 = zext i1 %t37 to i32 + store i32 %t38, ptr %t1 + br label %scend7 +scend7: + %t39 = load i32, ptr %t1 + %t40 = icmp ne i32 %t39, 0 + br i1 %t40, label %then8, label %ifend10 +then8: + store i32 1, ptr %retval + br label %ret +ifend10: + %t43 = load i32, ptr %t0 + %t44 = icmp eq i32 %t43, 60 + %t45 = zext i1 %t44 to i32 + %t46 = icmp ne i32 %t45, 0 + %t47 = zext i1 %t46 to i32 + store i32 %t47, ptr %t42 + br i1 %t46, label %scend12, label %sc11 +sc11: + %t48 = load i32, ptr %t0 + %t49 = icmp eq i32 %t48, 62 + %t50 = zext i1 %t49 to i32 + %t51 = icmp ne i32 %t50, 0 + %t52 = zext i1 %t51 to i32 + store i32 %t52, ptr %t42 + br label %scend12 +scend12: + %t53 = load i32, ptr %t42 + %t54 = icmp ne i32 %t53, 0 + %t55 = zext i1 %t54 to i32 + store i32 %t55, ptr %t41 + br i1 %t54, label %scend14, label %sc13 +sc13: + %t56 = load i32, ptr %t0 + %t57 = icmp eq i32 %t56, 61 + %t58 = zext i1 %t57 to i32 + %t59 = icmp ne i32 %t58, 0 + %t60 = zext i1 %t59 to i32 + store i32 %t60, ptr %t41 + br label %scend14 +scend14: + %t61 = load i32, ptr %t41 + %t62 = icmp ne i32 %t61, 0 + br i1 %t62, label %then15, label %ifend17 +then15: + store i32 1, ptr %retval + br label %ret +ifend17: + %t66 = load i32, ptr %t0 + %t67 = icmp eq i32 %t66, 40 + %t68 = zext i1 %t67 to i32 + %t69 = icmp ne i32 %t68, 0 + %t70 = zext i1 %t69 to i32 + store i32 %t70, ptr %t65 + br i1 %t69, label %scend19, label %sc18 +sc18: + %t71 = load i32, ptr %t0 + %t72 = icmp eq i32 %t71, 41 + %t73 = zext i1 %t72 to i32 + %t74 = icmp ne i32 %t73, 0 + %t75 = zext i1 %t74 to i32 + store i32 %t75, ptr %t65 + br label %scend19 +scend19: + %t76 = load i32, ptr %t65 + %t77 = icmp ne i32 %t76, 0 + %t78 = zext i1 %t77 to i32 + store i32 %t78, ptr %t64 + br i1 %t77, label %scend21, label %sc20 +sc20: + %t79 = load i32, ptr %t0 + %t80 = icmp eq i32 %t79, 123 + %t81 = zext i1 %t80 to i32 + %t82 = icmp ne i32 %t81, 0 + %t83 = zext i1 %t82 to i32 + store i32 %t83, ptr %t64 + br label %scend21 +scend21: + %t84 = load i32, ptr %t64 + %t85 = icmp ne i32 %t84, 0 + %t86 = zext i1 %t85 to i32 + store i32 %t86, ptr %t63 + br i1 %t85, label %scend23, label %sc22 +sc22: + %t87 = load i32, ptr %t0 + %t88 = icmp eq i32 %t87, 125 + %t89 = zext i1 %t88 to i32 + %t90 = icmp ne i32 %t89, 0 + %t91 = zext i1 %t90 to i32 + store i32 %t91, ptr %t63 + br label %scend23 +scend23: + %t92 = load i32, ptr %t63 + %t93 = icmp ne i32 %t92, 0 + br i1 %t93, label %then24, label %ifend26 +then24: + store i32 1, ptr %retval + br label %ret +ifend26: + %t98 = load i32, ptr %t0 + %t99 = icmp eq i32 %t98, 91 + %t100 = zext i1 %t99 to i32 + %t101 = icmp ne i32 %t100, 0 + %t102 = zext i1 %t101 to i32 + store i32 %t102, ptr %t97 + br i1 %t101, label %scend28, label %sc27 +sc27: + %t103 = load i32, ptr %t0 + %t104 = icmp eq i32 %t103, 93 + %t105 = zext i1 %t104 to i32 + %t106 = icmp ne i32 %t105, 0 + %t107 = zext i1 %t106 to i32 + store i32 %t107, ptr %t97 + br label %scend28 +scend28: + %t108 = load i32, ptr %t97 + %t109 = icmp ne i32 %t108, 0 + %t110 = zext i1 %t109 to i32 + store i32 %t110, ptr %t96 + br i1 %t109, label %scend30, label %sc29 +sc29: + %t111 = load i32, ptr %t0 + %t112 = icmp eq i32 %t111, 44 + %t113 = zext i1 %t112 to i32 + %t114 = icmp ne i32 %t113, 0 + %t115 = zext i1 %t114 to i32 + store i32 %t115, ptr %t96 + br label %scend30 +scend30: + %t116 = load i32, ptr %t96 + %t117 = icmp ne i32 %t116, 0 + %t118 = zext i1 %t117 to i32 + store i32 %t118, ptr %t95 + br i1 %t117, label %scend32, label %sc31 +sc31: + %t119 = load i32, ptr %t0 + %t120 = icmp eq i32 %t119, 58 + %t121 = zext i1 %t120 to i32 + %t122 = icmp ne i32 %t121, 0 + %t123 = zext i1 %t122 to i32 + store i32 %t123, ptr %t95 + br label %scend32 +scend32: + %t124 = load i32, ptr %t95 + %t125 = icmp ne i32 %t124, 0 + %t126 = zext i1 %t125 to i32 + store i32 %t126, ptr %t94 + br i1 %t125, label %scend34, label %sc33 +sc33: + %t127 = load i32, ptr %t0 + %t128 = icmp eq i32 %t127, 46 + %t129 = zext i1 %t128 to i32 + %t130 = icmp ne i32 %t129, 0 + %t131 = zext i1 %t130 to i32 + store i32 %t131, ptr %t94 + br label %scend34 +scend34: + %t132 = load i32, ptr %t94 + %t133 = icmp ne i32 %t132, 0 + br i1 %t133, label %then35, label %ifend37 +then35: + store i32 1, ptr %retval + br label %ret +ifend37: + %t135 = load i32, ptr %t0 + %t136 = icmp eq i32 %t135, 33 + %t137 = zext i1 %t136 to i32 + %t138 = icmp ne i32 %t137, 0 + %t139 = zext i1 %t138 to i32 + store i32 %t139, ptr %t134 + br i1 %t138, label %scend39, label %sc38 +sc38: + %t140 = load i32, ptr %t0 + %t141 = icmp eq i32 %t140, 64 + %t142 = zext i1 %t141 to i32 + %t143 = icmp ne i32 %t142, 0 + %t144 = zext i1 %t143 to i32 + store i32 %t144, ptr %t134 + br label %scend39 +scend39: + %t145 = load i32, ptr %t134 + %t146 = icmp ne i32 %t145, 0 + br i1 %t146, label %then40, label %ifend42 +then40: + store i32 1, ptr %retval + br label %ret +ifend42: + store i32 0, ptr %retval + br label %ret +ret: + %t147 = load i32, ptr %retval + ret i32 %t147 +} + +define void @fn_lex(ptr %arg_src) { +entry: + %t0 = alloca ptr + %t7 = alloca i32 + %t8 = alloca i32 + %t11 = alloca i32 + %t22 = alloca i32 + %t32 = alloca i32 + %t33 = alloca i32 + %t60 = alloca i32 + %t87 = alloca i32 + %t91 = alloca ptr + %t92 = alloca i32 + %t93 = alloca i32 + %t125 = alloca i32 + %t127 = alloca i32 + %t176 = alloca i32 + %t191 = alloca i32 + %t228 = alloca i32 + %t246 = alloca i32 + %t259 = alloca i32 + %t260 = alloca i32 + %t266 = alloca i32 + %t281 = alloca i32 + %t304 = alloca i32 + %t305 = alloca i32 + %t333 = alloca i32 + %t334 = alloca i32 + %t366 = alloca i32 + %t367 = alloca i32 + %t368 = alloca i32 + %t405 = alloca i32 + %t414 = alloca i32 + %t415 = alloca i32 + store ptr %arg_src, ptr %t0 + %t1 = getelementptr %LSlice, ptr null, i32 1 + %t2 = ptrtoint ptr %t1 to i64 + %t3 = call ptr @malloc(i64 %t2) + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 0 + store ptr null, ptr %t4 + %t5 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + store i32 0, ptr %t5 + %t6 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 2 + store i32 0, ptr %t6 + store ptr %t3, ptr @g_toks + store i32 0, ptr %t7 + store i32 1, ptr %t8 + %t9 = load ptr, ptr %t0 + %t10 = call i32 @fn_slen(ptr %t9) + store i32 %t10, ptr %t11 + br label %wcond0 +wcond0: + %t12 = load i32, ptr %t7 + %t13 = load i32, ptr %t11 + %t14 = icmp slt i32 %t12, %t13 + %t15 = zext i1 %t14 to i32 + %t16 = icmp ne i32 %t15, 0 + br i1 %t16, label %wbody1, label %wend2 +wbody1: + %t17 = load ptr, ptr %t0 + %t18 = load i32, ptr %t7 + %t19 = getelementptr inbounds i8, ptr %t17, i32 %t18 + %t20 = load i8, ptr %t19 + %t21 = zext i8 %t20 to i32 + store i32 %t21, ptr %t22 + %t23 = load i32, ptr %t22 + %t24 = icmp eq i32 %t23, 10 + %t25 = zext i1 %t24 to i32 + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %then3, label %ifend5 +then3: + %t27 = load i32, ptr %t8 + call void @fn_tok_push(i32 4, ptr null, i32 0, i32 %t27) + %t28 = load i32, ptr %t8 + %t29 = add i32 %t28, 1 + store i32 %t29, ptr %t8 + %t30 = load i32, ptr %t7 + %t31 = add i32 %t30, 1 + store i32 %t31, ptr %t7 + br label %wcond0 +ifend5: + %t34 = load i32, ptr %t22 + %t35 = icmp eq i32 %t34, 32 + %t36 = zext i1 %t35 to i32 + %t37 = icmp ne i32 %t36, 0 + %t38 = zext i1 %t37 to i32 + store i32 %t38, ptr %t33 + br i1 %t37, label %scend7, label %sc6 +sc6: + %t39 = load i32, ptr %t22 + %t40 = icmp eq i32 %t39, 9 + %t41 = zext i1 %t40 to i32 + %t42 = icmp ne i32 %t41, 0 + %t43 = zext i1 %t42 to i32 + store i32 %t43, ptr %t33 + br label %scend7 +scend7: + %t44 = load i32, ptr %t33 + %t45 = icmp ne i32 %t44, 0 + %t46 = zext i1 %t45 to i32 + store i32 %t46, ptr %t32 + br i1 %t45, label %scend9, label %sc8 +sc8: + %t47 = load i32, ptr %t22 + %t48 = icmp eq i32 %t47, 13 + %t49 = zext i1 %t48 to i32 + %t50 = icmp ne i32 %t49, 0 + %t51 = zext i1 %t50 to i32 + store i32 %t51, ptr %t32 + br label %scend9 +scend9: + %t52 = load i32, ptr %t32 + %t53 = icmp ne i32 %t52, 0 + br i1 %t53, label %then10, label %ifend12 +then10: + %t54 = load i32, ptr %t7 + %t55 = add i32 %t54, 1 + store i32 %t55, ptr %t7 + br label %wcond0 +ifend12: + %t56 = load i32, ptr %t22 + %t57 = icmp eq i32 %t56, 35 + %t58 = zext i1 %t57 to i32 + %t59 = icmp ne i32 %t58, 0 + br i1 %t59, label %then13, label %ifend15 +then13: + br label %wcond16 +wcond16: + %t61 = load i32, ptr %t7 + %t62 = load i32, ptr %t11 + %t63 = icmp slt i32 %t61, %t62 + %t64 = zext i1 %t63 to i32 + %t65 = icmp ne i32 %t64, 0 + %t66 = zext i1 %t65 to i32 + store i32 %t66, ptr %t60 + br i1 %t65, label %sc19, label %scend20 +sc19: + %t67 = load ptr, ptr %t0 + %t68 = load i32, ptr %t7 + %t69 = getelementptr inbounds i8, ptr %t67, i32 %t68 + %t70 = load i8, ptr %t69 + %t71 = zext i8 %t70 to i32 + %t72 = icmp ne i32 %t71, 10 + %t73 = zext i1 %t72 to i32 + %t74 = icmp ne i32 %t73, 0 + %t75 = zext i1 %t74 to i32 + store i32 %t75, ptr %t60 + br label %scend20 +scend20: + %t76 = load i32, ptr %t60 + %t77 = icmp ne i32 %t76, 0 + br i1 %t77, label %wbody17, label %wend18 +wbody17: + %t78 = load i32, ptr %t7 + %t79 = add i32 %t78, 1 + store i32 %t79, ptr %t7 + br label %wcond16 +wend18: + br label %wcond0 +ifend15: + %t80 = load i32, ptr %t22 + %t81 = icmp eq i32 %t80, 34 + %t82 = zext i1 %t81 to i32 + %t83 = icmp ne i32 %t82, 0 + br i1 %t83, label %then21, label %ifend23 +then21: + %t84 = load i32, ptr %t7 + %t85 = add i32 %t84, 1 + store i32 %t85, ptr %t7 + %t86 = load i32, ptr %t7 + store i32 %t86, ptr %t87 + %t88 = load i32, ptr %t11 + %t89 = zext i32 %t88 to i64 + %t90 = call ptr @malloc(i64 %t89) + store ptr %t90, ptr %t91 + store i32 0, ptr %t92 + br label %wcond24 +wcond24: + %t94 = load i32, ptr %t7 + %t95 = load i32, ptr %t11 + %t96 = icmp slt i32 %t94, %t95 + %t97 = zext i1 %t96 to i32 + %t98 = icmp ne i32 %t97, 0 + %t99 = zext i1 %t98 to i32 + store i32 %t99, ptr %t93 + br i1 %t98, label %sc27, label %scend28 +sc27: + %t100 = load ptr, ptr %t0 + %t101 = load i32, ptr %t7 + %t102 = getelementptr inbounds i8, ptr %t100, i32 %t101 + %t103 = load i8, ptr %t102 + %t104 = zext i8 %t103 to i32 + %t105 = icmp ne i32 %t104, 34 + %t106 = zext i1 %t105 to i32 + %t107 = icmp ne i32 %t106, 0 + %t108 = zext i1 %t107 to i32 + store i32 %t108, ptr %t93 + br label %scend28 +scend28: + %t109 = load i32, ptr %t93 + %t110 = icmp ne i32 %t109, 0 + br i1 %t110, label %wbody25, label %wend26 +wbody25: + %t111 = load ptr, ptr %t0 + %t112 = load i32, ptr %t7 + %t113 = getelementptr inbounds i8, ptr %t111, i32 %t112 + %t114 = load i8, ptr %t113 + %t115 = zext i8 %t114 to i32 + %t116 = icmp eq i32 %t115, 92 + %t117 = zext i1 %t116 to i32 + %t118 = icmp ne i32 %t117, 0 + br i1 %t118, label %then29, label %else30 +then29: + %t119 = load ptr, ptr %t0 + %t120 = load i32, ptr %t7 + %t121 = add i32 %t120, 1 + %t122 = getelementptr inbounds i8, ptr %t119, i32 %t121 + %t123 = load i8, ptr %t122 + %t124 = zext i8 %t123 to i32 + store i32 %t124, ptr %t125 + %t126 = load i32, ptr %t125 + store i32 %t126, ptr %t127 + %t128 = load i32, ptr %t125 + %t129 = icmp eq i32 %t128, 110 + %t130 = zext i1 %t129 to i32 + %t131 = icmp ne i32 %t130, 0 + br i1 %t131, label %then32, label %ifend34 +then32: + store i32 10, ptr %t127 + br label %ifend34 +ifend34: + %t132 = load i32, ptr %t125 + %t133 = icmp eq i32 %t132, 116 + %t134 = zext i1 %t133 to i32 + %t135 = icmp ne i32 %t134, 0 + br i1 %t135, label %then35, label %ifend37 +then35: + store i32 9, ptr %t127 + br label %ifend37 +ifend37: + %t136 = load i32, ptr %t125 + %t137 = icmp eq i32 %t136, 48 + %t138 = zext i1 %t137 to i32 + %t139 = icmp ne i32 %t138, 0 + br i1 %t139, label %then38, label %ifend40 +then38: + store i32 0, ptr %t127 + br label %ifend40 +ifend40: + %t140 = load ptr, ptr %t91 + %t141 = load i32, ptr %t92 + %t142 = load i32, ptr %t127 + %t143 = getelementptr inbounds i8, ptr %t140, i32 %t141 + %t144 = trunc i32 %t142 to i8 + store i8 %t144, ptr %t143 + %t145 = load i32, ptr %t92 + %t146 = add i32 %t145, 1 + store i32 %t146, ptr %t92 + %t147 = load i32, ptr %t7 + %t148 = add i32 %t147, 2 + store i32 %t148, ptr %t7 + br label %ifend31 +else30: + %t149 = load ptr, ptr %t91 + %t150 = load i32, ptr %t92 + %t151 = load ptr, ptr %t0 + %t152 = load i32, ptr %t7 + %t153 = getelementptr inbounds i8, ptr %t151, i32 %t152 + %t154 = load i8, ptr %t153 + %t155 = zext i8 %t154 to i32 + %t156 = getelementptr inbounds i8, ptr %t149, i32 %t150 + %t157 = trunc i32 %t155 to i8 + store i8 %t157, ptr %t156 + %t158 = load i32, ptr %t92 + %t159 = add i32 %t158, 1 + store i32 %t159, ptr %t92 + %t160 = load i32, ptr %t7 + %t161 = add i32 %t160, 1 + store i32 %t161, ptr %t7 + br label %ifend31 +ifend31: + br label %wcond24 +wend26: + %t162 = load i32, ptr %t7 + %t163 = add i32 %t162, 1 + store i32 %t163, ptr %t7 + %t164 = load ptr, ptr %t91 + %t165 = load i32, ptr %t92 + %t166 = getelementptr inbounds i8, ptr %t164, i32 %t165 + %t167 = trunc i32 0 to i8 + store i8 %t167, ptr %t166 + %t168 = load ptr, ptr %t91 + %t169 = load i32, ptr %t8 + call void @fn_tok_push(i32 2, ptr %t168, i32 0, i32 %t169) + br label %wcond0 +ifend23: + %t170 = load i32, ptr %t22 + %t171 = icmp eq i32 %t170, 39 + %t172 = zext i1 %t171 to i32 + %t173 = icmp ne i32 %t172, 0 + br i1 %t173, label %then41, label %ifend43 +then41: + %t174 = load i32, ptr %t7 + %t175 = add i32 %t174, 1 + store i32 %t175, ptr %t7 + store i32 0, ptr %t176 + %t177 = load ptr, ptr %t0 + %t178 = load i32, ptr %t7 + %t179 = getelementptr inbounds i8, ptr %t177, i32 %t178 + %t180 = load i8, ptr %t179 + %t181 = zext i8 %t180 to i32 + %t182 = icmp eq i32 %t181, 92 + %t183 = zext i1 %t182 to i32 + %t184 = icmp ne i32 %t183, 0 + br i1 %t184, label %then44, label %else45 +then44: + %t185 = load ptr, ptr %t0 + %t186 = load i32, ptr %t7 + %t187 = add i32 %t186, 1 + %t188 = getelementptr inbounds i8, ptr %t185, i32 %t187 + %t189 = load i8, ptr %t188 + %t190 = zext i8 %t189 to i32 + store i32 %t190, ptr %t191 + %t192 = load i32, ptr %t191 + %t193 = icmp eq i32 %t192, 110 + %t194 = zext i1 %t193 to i32 + %t195 = icmp ne i32 %t194, 0 + br i1 %t195, label %then47, label %ifend49 +then47: + store i32 10, ptr %t176 + br label %ifend49 +ifend49: + %t196 = load i32, ptr %t191 + %t197 = icmp eq i32 %t196, 116 + %t198 = zext i1 %t197 to i32 + %t199 = icmp ne i32 %t198, 0 + br i1 %t199, label %then50, label %ifend52 +then50: + store i32 9, ptr %t176 + br label %ifend52 +ifend52: + %t200 = load i32, ptr %t191 + %t201 = icmp eq i32 %t200, 48 + %t202 = zext i1 %t201 to i32 + %t203 = icmp ne i32 %t202, 0 + br i1 %t203, label %then53, label %ifend55 +then53: + store i32 0, ptr %t176 + br label %ifend55 +ifend55: + %t204 = load i32, ptr %t7 + %t205 = add i32 %t204, 2 + store i32 %t205, ptr %t7 + br label %ifend46 +else45: + %t206 = load ptr, ptr %t0 + %t207 = load i32, ptr %t7 + %t208 = getelementptr inbounds i8, ptr %t206, i32 %t207 + %t209 = load i8, ptr %t208 + %t210 = zext i8 %t209 to i32 + store i32 %t210, ptr %t176 + %t211 = load i32, ptr %t7 + %t212 = add i32 %t211, 1 + store i32 %t212, ptr %t7 + br label %ifend46 +ifend46: + %t213 = load ptr, ptr %t0 + %t214 = load i32, ptr %t7 + %t215 = getelementptr inbounds i8, ptr %t213, i32 %t214 + %t216 = load i8, ptr %t215 + %t217 = zext i8 %t216 to i32 + %t218 = icmp eq i32 %t217, 39 + %t219 = zext i1 %t218 to i32 + %t220 = icmp ne i32 %t219, 0 + br i1 %t220, label %then56, label %ifend58 +then56: + %t221 = load i32, ptr %t7 + %t222 = add i32 %t221, 1 + store i32 %t222, ptr %t7 + br label %ifend58 +ifend58: + %t223 = load i32, ptr %t176 + %t224 = load i32, ptr %t8 + call void @fn_tok_push(i32 1, ptr null, i32 %t223, i32 %t224) + br label %wcond0 +ifend43: + %t225 = load i32, ptr %t22 + %t226 = call i32 @fn_char_is_digit(i32 %t225) + %t227 = icmp ne i32 %t226, 0 + br i1 %t227, label %then59, label %ifend61 +then59: + %t229 = load i32, ptr %t22 + %t230 = icmp eq i32 %t229, 48 + %t231 = zext i1 %t230 to i32 + %t232 = icmp ne i32 %t231, 0 + %t233 = zext i1 %t232 to i32 + store i32 %t233, ptr %t228 + br i1 %t232, label %sc62, label %scend63 +sc62: + %t234 = load ptr, ptr %t0 + %t235 = load i32, ptr %t7 + %t236 = add i32 %t235, 1 + %t237 = getelementptr inbounds i8, ptr %t234, i32 %t236 + %t238 = load i8, ptr %t237 + %t239 = zext i8 %t238 to i32 + %t240 = icmp eq i32 %t239, 120 + %t241 = zext i1 %t240 to i32 + %t242 = icmp ne i32 %t241, 0 + %t243 = zext i1 %t242 to i32 + store i32 %t243, ptr %t228 + br label %scend63 +scend63: + %t244 = load i32, ptr %t228 + %t245 = icmp ne i32 %t244, 0 + br i1 %t245, label %then64, label %ifend66 +then64: + store i32 0, ptr %t246 + %t247 = load i32, ptr %t7 + %t248 = add i32 %t247, 2 + store i32 %t248, ptr %t7 + br label %wcond67 +wcond67: + %t249 = load i32, ptr %t7 + %t250 = load i32, ptr %t11 + %t251 = icmp slt i32 %t249, %t250 + %t252 = zext i1 %t251 to i32 + %t253 = icmp ne i32 %t252, 0 + br i1 %t253, label %wbody68, label %wend69 +wbody68: + %t254 = load ptr, ptr %t0 + %t255 = load i32, ptr %t7 + %t256 = getelementptr inbounds i8, ptr %t254, i32 %t255 + %t257 = load i8, ptr %t256 + %t258 = zext i8 %t257 to i32 + store i32 %t258, ptr %t259 + store i32 0, ptr %t260 + %t261 = load i32, ptr %t259 + %t262 = call i32 @fn_char_is_digit(i32 %t261) + %t263 = icmp ne i32 %t262, 0 + br i1 %t263, label %then70, label %else71 +then70: + %t264 = load i32, ptr %t259 + %t265 = sub i32 %t264, 48 + store i32 %t265, ptr %t260 + br label %ifend72 +else71: + %t267 = load i32, ptr %t259 + %t268 = icmp sge i32 %t267, 97 + %t269 = zext i1 %t268 to i32 + %t270 = icmp ne i32 %t269, 0 + %t271 = zext i1 %t270 to i32 + store i32 %t271, ptr %t266 + br i1 %t270, label %sc73, label %scend74 +sc73: + %t272 = load i32, ptr %t259 + %t273 = icmp sle i32 %t272, 102 + %t274 = zext i1 %t273 to i32 + %t275 = icmp ne i32 %t274, 0 + %t276 = zext i1 %t275 to i32 + store i32 %t276, ptr %t266 + br label %scend74 +scend74: + %t277 = load i32, ptr %t266 + %t278 = icmp ne i32 %t277, 0 + br i1 %t278, label %then75, label %else76 +then75: + %t279 = load i32, ptr %t259 + %t280 = sub i32 %t279, 87 + store i32 %t280, ptr %t260 + br label %ifend77 +else76: + %t282 = load i32, ptr %t259 + %t283 = icmp sge i32 %t282, 65 + %t284 = zext i1 %t283 to i32 + %t285 = icmp ne i32 %t284, 0 + %t286 = zext i1 %t285 to i32 + store i32 %t286, ptr %t281 + br i1 %t285, label %sc78, label %scend79 +sc78: + %t287 = load i32, ptr %t259 + %t288 = icmp sle i32 %t287, 70 + %t289 = zext i1 %t288 to i32 + %t290 = icmp ne i32 %t289, 0 + %t291 = zext i1 %t290 to i32 + store i32 %t291, ptr %t281 + br label %scend79 +scend79: + %t292 = load i32, ptr %t281 + %t293 = icmp ne i32 %t292, 0 + br i1 %t293, label %then80, label %else81 +then80: + %t294 = load i32, ptr %t259 + %t295 = sub i32 %t294, 55 + store i32 %t295, ptr %t260 + br label %ifend82 +else81: + br label %wend69 +ifend82: + br label %ifend77 +ifend77: + br label %ifend72 +ifend72: + %t296 = load i32, ptr %t246 + %t297 = mul i32 %t296, 16 + %t298 = load i32, ptr %t260 + %t299 = add i32 %t297, %t298 + store i32 %t299, ptr %t246 + %t300 = load i32, ptr %t7 + %t301 = add i32 %t300, 1 + store i32 %t301, ptr %t7 + br label %wcond67 +wend69: + %t302 = load i32, ptr %t246 + %t303 = load i32, ptr %t8 + call void @fn_tok_push(i32 1, ptr null, i32 %t302, i32 %t303) + br label %wcond0 +ifend66: + store i32 0, ptr %t304 + br label %wcond83 +wcond83: + %t306 = load i32, ptr %t7 + %t307 = load i32, ptr %t11 + %t308 = icmp slt i32 %t306, %t307 + %t309 = zext i1 %t308 to i32 + %t310 = icmp ne i32 %t309, 0 + %t311 = zext i1 %t310 to i32 + store i32 %t311, ptr %t305 + br i1 %t310, label %sc86, label %scend87 +sc86: + %t312 = load ptr, ptr %t0 + %t313 = load i32, ptr %t7 + %t314 = getelementptr inbounds i8, ptr %t312, i32 %t313 + %t315 = load i8, ptr %t314 + %t316 = zext i8 %t315 to i32 + %t317 = call i32 @fn_char_is_digit(i32 %t316) + %t318 = icmp ne i32 %t317, 0 + %t319 = zext i1 %t318 to i32 + store i32 %t319, ptr %t305 + br label %scend87 +scend87: + %t320 = load i32, ptr %t305 + %t321 = icmp ne i32 %t320, 0 + br i1 %t321, label %wbody84, label %wend85 +wbody84: + %t322 = load i32, ptr %t304 + %t323 = mul i32 %t322, 10 + %t324 = load ptr, ptr %t0 + %t325 = load i32, ptr %t7 + %t326 = getelementptr inbounds i8, ptr %t324, i32 %t325 + %t327 = load i8, ptr %t326 + %t328 = zext i8 %t327 to i32 + %t329 = sub i32 %t328, 48 + %t330 = add i32 %t323, %t329 + store i32 %t330, ptr %t304 + %t331 = load i32, ptr %t7 + %t332 = add i32 %t331, 1 + store i32 %t332, ptr %t7 + br label %wcond83 +wend85: + %t335 = load i32, ptr %t7 + %t336 = load i32, ptr %t11 + %t337 = icmp slt i32 %t335, %t336 + %t338 = zext i1 %t337 to i32 + %t339 = icmp ne i32 %t338, 0 + %t340 = zext i1 %t339 to i32 + store i32 %t340, ptr %t334 + br i1 %t339, label %sc88, label %scend89 +sc88: + %t341 = load ptr, ptr %t0 + %t342 = load i32, ptr %t7 + %t343 = getelementptr inbounds i8, ptr %t341, i32 %t342 + %t344 = load i8, ptr %t343 + %t345 = zext i8 %t344 to i32 + %t346 = icmp eq i32 %t345, 46 + %t347 = zext i1 %t346 to i32 + %t348 = icmp ne i32 %t347, 0 + %t349 = zext i1 %t348 to i32 + store i32 %t349, ptr %t334 + br label %scend89 +scend89: + %t350 = load i32, ptr %t334 + %t351 = icmp ne i32 %t350, 0 + %t352 = zext i1 %t351 to i32 + store i32 %t352, ptr %t333 + br i1 %t351, label %sc90, label %scend91 +sc90: + %t353 = load ptr, ptr %t0 + %t354 = load i32, ptr %t7 + %t355 = add i32 %t354, 1 + %t356 = getelementptr inbounds i8, ptr %t353, i32 %t355 + %t357 = load i8, ptr %t356 + %t358 = zext i8 %t357 to i32 + %t359 = call i32 @fn_char_is_digit(i32 %t358) + %t360 = icmp ne i32 %t359, 0 + %t361 = zext i1 %t360 to i32 + store i32 %t361, ptr %t333 + br label %scend91 +scend91: + %t362 = load i32, ptr %t333 + %t363 = icmp ne i32 %t362, 0 + br i1 %t363, label %then92, label %ifend94 +then92: + %t364 = load i32, ptr %t7 + %t365 = add i32 %t364, 1 + store i32 %t365, ptr %t7 + store i32 0, ptr %t366 + store i32 1, ptr %t367 + br label %wcond95 +wcond95: + %t369 = load i32, ptr %t7 + %t370 = load i32, ptr %t11 + %t371 = icmp slt i32 %t369, %t370 + %t372 = zext i1 %t371 to i32 + %t373 = icmp ne i32 %t372, 0 + %t374 = zext i1 %t373 to i32 + store i32 %t374, ptr %t368 + br i1 %t373, label %sc98, label %scend99 +sc98: + %t375 = load ptr, ptr %t0 + %t376 = load i32, ptr %t7 + %t377 = getelementptr inbounds i8, ptr %t375, i32 %t376 + %t378 = load i8, ptr %t377 + %t379 = zext i8 %t378 to i32 + %t380 = call i32 @fn_char_is_digit(i32 %t379) + %t381 = icmp ne i32 %t380, 0 + %t382 = zext i1 %t381 to i32 + store i32 %t382, ptr %t368 + br label %scend99 +scend99: + %t383 = load i32, ptr %t368 + %t384 = icmp ne i32 %t383, 0 + br i1 %t384, label %wbody96, label %wend97 +wbody96: + %t385 = load i32, ptr %t366 + %t386 = mul i32 %t385, 10 + %t387 = load ptr, ptr %t0 + %t388 = load i32, ptr %t7 + %t389 = getelementptr inbounds i8, ptr %t387, i32 %t388 + %t390 = load i8, ptr %t389 + %t391 = zext i8 %t390 to i32 + %t392 = sub i32 %t391, 48 + %t393 = add i32 %t386, %t392 + store i32 %t393, ptr %t366 + %t394 = load i32, ptr %t367 + %t395 = mul i32 %t394, 10 + store i32 %t395, ptr %t367 + %t396 = load i32, ptr %t7 + %t397 = add i32 %t396, 1 + store i32 %t397, ptr %t7 + br label %wcond95 +wend97: + %t398 = load i32, ptr %t304 + %t399 = shl i32 %t398, 16 + %t400 = load i32, ptr %t366 + %t401 = shl i32 %t400, 16 + %t402 = load i32, ptr %t367 + %t403 = sdiv i32 %t401, %t402 + %t404 = add i32 %t399, %t403 + store i32 %t404, ptr %t405 + %t406 = load i32, ptr %t405 + %t407 = load i32, ptr %t8 + call void @fn_tok_push(i32 6, ptr null, i32 %t406, i32 %t407) + br label %wcond0 +ifend94: + %t408 = load i32, ptr %t304 + %t409 = load i32, ptr %t8 + call void @fn_tok_push(i32 1, ptr null, i32 %t408, i32 %t409) + br label %wcond0 +ifend61: + %t410 = load i32, ptr %t22 + %t411 = call i32 @fn_char_is_alpha(i32 %t410) + %t412 = icmp ne i32 %t411, 0 + br i1 %t412, label %then100, label %ifend102 +then100: + %t413 = load i32, ptr %t7 + store i32 %t413, ptr %t414 + br label %wcond103 +wcond103: + %t416 = load i32, ptr %t7 + %t417 = load i32, ptr %t11 + %t418 = icmp slt i32 %t416, %t417 + %t419 = zext i1 %t418 to i32 + %t420 = icmp ne i32 %t419, 0 + %t421 = zext i1 %t420 to i32 + store i32 %t421, ptr %t415 + br i1 %t420, label %sc106, label %scend107 +sc106: + %t422 = load ptr, ptr %t0 + %t423 = load i32, ptr %t7 + %t424 = getelementptr inbounds i8, ptr %t422, i32 %t423 + %t425 = load i8, ptr %t424 + %t426 = zext i8 %t425 to i32 + %t427 = call i32 @fn_char_is_alnum(i32 %t426) + %t428 = icmp ne i32 %t427, 0 + %t429 = zext i1 %t428 to i32 + store i32 %t429, ptr %t415 + br label %scend107 +scend107: + %t430 = load i32, ptr %t415 + %t431 = icmp ne i32 %t430, 0 + br i1 %t431, label %wbody104, label %wend105 +wbody104: + %t432 = load i32, ptr %t7 + %t433 = add i32 %t432, 1 + store i32 %t433, ptr %t7 + br label %wcond103 +wend105: + %t434 = load ptr, ptr %t0 + %t435 = load i32, ptr %t414 + %t436 = load i32, ptr %t7 + %t437 = load i32, ptr %t414 + %t438 = sub i32 %t436, %t437 + %t439 = call ptr @fn_substr(ptr %t434, i32 %t435, i32 %t438) + %t440 = load i32, ptr %t8 + call void @fn_tok_push(i32 0, ptr %t439, i32 0, i32 %t440) + br label %wcond0 +ifend102: + %t441 = load i32, ptr %t22 + %t442 = icmp eq i32 %t441, 59 + %t443 = zext i1 %t442 to i32 + %t444 = icmp ne i32 %t443, 0 + br i1 %t444, label %then108, label %ifend110 +then108: + %t445 = load i32, ptr %t8 + call void @fn_tok_push(i32 4, ptr null, i32 0, i32 %t445) + %t446 = load i32, ptr %t7 + %t447 = add i32 %t446, 1 + store i32 %t447, ptr %t7 + br label %wcond0 +ifend110: + %t448 = load ptr, ptr %t0 + %t449 = load i32, ptr %t7 + %t450 = call i32 @fn_two_at(ptr %t448, i32 %t449, i32 45, i32 62) + %t451 = icmp ne i32 %t450, 0 + br i1 %t451, label %then111, label %ifend113 +then111: + %t452 = load ptr, ptr %t0 + %t453 = load i32, ptr %t7 + %t454 = call ptr @fn_substr(ptr %t452, i32 %t453, i32 2) + %t455 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t454, i32 0, i32 %t455) + %t456 = load i32, ptr %t7 + %t457 = add i32 %t456, 2 + store i32 %t457, ptr %t7 + br label %wcond0 +ifend113: + %t458 = load ptr, ptr %t0 + %t459 = load i32, ptr %t7 + %t460 = call i32 @fn_two_at(ptr %t458, i32 %t459, i32 61, i32 62) + %t461 = icmp ne i32 %t460, 0 + br i1 %t461, label %then114, label %ifend116 +then114: + %t462 = load ptr, ptr %t0 + %t463 = load i32, ptr %t7 + %t464 = call ptr @fn_substr(ptr %t462, i32 %t463, i32 2) + %t465 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t464, i32 0, i32 %t465) + %t466 = load i32, ptr %t7 + %t467 = add i32 %t466, 2 + store i32 %t467, ptr %t7 + br label %wcond0 +ifend116: + %t468 = load ptr, ptr %t0 + %t469 = load i32, ptr %t7 + %t470 = call i32 @fn_two_at(ptr %t468, i32 %t469, i32 61, i32 61) + %t471 = icmp ne i32 %t470, 0 + br i1 %t471, label %then117, label %ifend119 +then117: + %t472 = load ptr, ptr %t0 + %t473 = load i32, ptr %t7 + %t474 = call ptr @fn_substr(ptr %t472, i32 %t473, i32 2) + %t475 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t474, i32 0, i32 %t475) + %t476 = load i32, ptr %t7 + %t477 = add i32 %t476, 2 + store i32 %t477, ptr %t7 + br label %wcond0 +ifend119: + %t478 = load ptr, ptr %t0 + %t479 = load i32, ptr %t7 + %t480 = call i32 @fn_two_at(ptr %t478, i32 %t479, i32 33, i32 61) + %t481 = icmp ne i32 %t480, 0 + br i1 %t481, label %then120, label %ifend122 +then120: + %t482 = load ptr, ptr %t0 + %t483 = load i32, ptr %t7 + %t484 = call ptr @fn_substr(ptr %t482, i32 %t483, i32 2) + %t485 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t484, i32 0, i32 %t485) + %t486 = load i32, ptr %t7 + %t487 = add i32 %t486, 2 + store i32 %t487, ptr %t7 + br label %wcond0 +ifend122: + %t488 = load ptr, ptr %t0 + %t489 = load i32, ptr %t7 + %t490 = call i32 @fn_two_at(ptr %t488, i32 %t489, i32 60, i32 61) + %t491 = icmp ne i32 %t490, 0 + br i1 %t491, label %then123, label %ifend125 +then123: + %t492 = load ptr, ptr %t0 + %t493 = load i32, ptr %t7 + %t494 = call ptr @fn_substr(ptr %t492, i32 %t493, i32 2) + %t495 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t494, i32 0, i32 %t495) + %t496 = load i32, ptr %t7 + %t497 = add i32 %t496, 2 + store i32 %t497, ptr %t7 + br label %wcond0 +ifend125: + %t498 = load ptr, ptr %t0 + %t499 = load i32, ptr %t7 + %t500 = call i32 @fn_two_at(ptr %t498, i32 %t499, i32 62, i32 61) + %t501 = icmp ne i32 %t500, 0 + br i1 %t501, label %then126, label %ifend128 +then126: + %t502 = load ptr, ptr %t0 + %t503 = load i32, ptr %t7 + %t504 = call ptr @fn_substr(ptr %t502, i32 %t503, i32 2) + %t505 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t504, i32 0, i32 %t505) + %t506 = load i32, ptr %t7 + %t507 = add i32 %t506, 2 + store i32 %t507, ptr %t7 + br label %wcond0 +ifend128: + %t508 = load ptr, ptr %t0 + %t509 = load i32, ptr %t7 + %t510 = call i32 @fn_two_at(ptr %t508, i32 %t509, i32 43, i32 61) + %t511 = icmp ne i32 %t510, 0 + br i1 %t511, label %then129, label %ifend131 +then129: + %t512 = load ptr, ptr %t0 + %t513 = load i32, ptr %t7 + %t514 = call ptr @fn_substr(ptr %t512, i32 %t513, i32 2) + %t515 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t514, i32 0, i32 %t515) + %t516 = load i32, ptr %t7 + %t517 = add i32 %t516, 2 + store i32 %t517, ptr %t7 + br label %wcond0 +ifend131: + %t518 = load ptr, ptr %t0 + %t519 = load i32, ptr %t7 + %t520 = call i32 @fn_two_at(ptr %t518, i32 %t519, i32 45, i32 61) + %t521 = icmp ne i32 %t520, 0 + br i1 %t521, label %then132, label %ifend134 +then132: + %t522 = load ptr, ptr %t0 + %t523 = load i32, ptr %t7 + %t524 = call ptr @fn_substr(ptr %t522, i32 %t523, i32 2) + %t525 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t524, i32 0, i32 %t525) + %t526 = load i32, ptr %t7 + %t527 = add i32 %t526, 2 + store i32 %t527, ptr %t7 + br label %wcond0 +ifend134: + %t528 = load ptr, ptr %t0 + %t529 = load i32, ptr %t7 + %t530 = call i32 @fn_two_at(ptr %t528, i32 %t529, i32 42, i32 61) + %t531 = icmp ne i32 %t530, 0 + br i1 %t531, label %then135, label %ifend137 +then135: + %t532 = load ptr, ptr %t0 + %t533 = load i32, ptr %t7 + %t534 = call ptr @fn_substr(ptr %t532, i32 %t533, i32 2) + %t535 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t534, i32 0, i32 %t535) + %t536 = load i32, ptr %t7 + %t537 = add i32 %t536, 2 + store i32 %t537, ptr %t7 + br label %wcond0 +ifend137: + %t538 = load ptr, ptr %t0 + %t539 = load i32, ptr %t7 + %t540 = call i32 @fn_two_at(ptr %t538, i32 %t539, i32 47, i32 61) + %t541 = icmp ne i32 %t540, 0 + br i1 %t541, label %then138, label %ifend140 +then138: + %t542 = load ptr, ptr %t0 + %t543 = load i32, ptr %t7 + %t544 = call ptr @fn_substr(ptr %t542, i32 %t543, i32 2) + %t545 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t544, i32 0, i32 %t545) + %t546 = load i32, ptr %t7 + %t547 = add i32 %t546, 2 + store i32 %t547, ptr %t7 + br label %wcond0 +ifend140: + %t548 = load ptr, ptr %t0 + %t549 = load i32, ptr %t7 + %t550 = call i32 @fn_two_at(ptr %t548, i32 %t549, i32 46, i32 46) + %t551 = icmp ne i32 %t550, 0 + br i1 %t551, label %then141, label %ifend143 +then141: + %t552 = load ptr, ptr %t0 + %t553 = load i32, ptr %t7 + %t554 = call ptr @fn_substr(ptr %t552, i32 %t553, i32 2) + %t555 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t554, i32 0, i32 %t555) + %t556 = load i32, ptr %t7 + %t557 = add i32 %t556, 2 + store i32 %t557, ptr %t7 + br label %wcond0 +ifend143: + %t558 = load i32, ptr %t22 + %t559 = call i32 @fn_is_op1(i32 %t558) + %t560 = icmp ne i32 %t559, 0 + br i1 %t560, label %then144, label %ifend146 +then144: + %t561 = load ptr, ptr %t0 + %t562 = load i32, ptr %t7 + %t563 = call ptr @fn_substr(ptr %t561, i32 %t562, i32 1) + %t564 = load i32, ptr %t8 + call void @fn_tok_push(i32 3, ptr %t563, i32 0, i32 %t564) + %t565 = load i32, ptr %t7 + %t566 = add i32 %t565, 1 + store i32 %t566, ptr %t7 + br label %wcond0 +ifend146: + %t567 = load i32, ptr %t7 + %t568 = add i32 %t567, 1 + store i32 %t568, ptr %t7 + br label %wcond0 +wend2: + %t569 = load i32, ptr %t8 + call void @fn_tok_push(i32 5, ptr null, i32 0, i32 %t569) + br label %ret +ret: + ret void +} + +define ptr @fn_cur() { +entry: + %retval = alloca ptr + %t0 = load ptr, ptr @g_toks + %t1 = getelementptr inbounds %LSlice, ptr %t0, i32 0, i32 0 + %t2 = load ptr, ptr %t1 + %t3 = load i32, ptr @g_pi + %t4 = getelementptr inbounds ptr, ptr %t2, i32 %t3 + %t5 = load ptr, ptr %t4 + store ptr %t5, ptr %retval + br label %ret +ret: + %t6 = load ptr, ptr %retval + ret ptr %t6 +} + +define ptr @fn_pk(i32 %arg_o) { +entry: + %retval = alloca ptr + %t0 = alloca i32 + store i32 %arg_o, ptr %t0 + %t1 = load ptr, ptr @g_toks + %t2 = getelementptr inbounds %LSlice, ptr %t1, i32 0, i32 0 + %t3 = load ptr, ptr %t2 + %t4 = load i32, ptr @g_pi + %t5 = load i32, ptr %t0 + %t6 = add i32 %t4, %t5 + %t7 = getelementptr inbounds ptr, ptr %t3, i32 %t6 + %t8 = load ptr, ptr %t7 + store ptr %t8, ptr %retval + br label %ret +ret: + %t9 = load ptr, ptr %retval + ret ptr %t9 +} + +define i32 @fn_is_op(ptr %arg_v) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t7 = alloca ptr + %t8 = alloca i32 + store ptr %arg_v, ptr %t0 + %t1 = load ptr, ptr @g_toks + %t2 = getelementptr inbounds %LSlice, ptr %t1, i32 0, i32 0 + %t3 = load ptr, ptr %t2 + %t4 = load i32, ptr @g_pi + %t5 = getelementptr inbounds ptr, ptr %t3, i32 %t4 + %t6 = load ptr, ptr %t5 + store ptr %t6, ptr %t7 + %t9 = load ptr, ptr %t7 + %t10 = getelementptr inbounds %Str_Tok, ptr %t9, i32 0, i32 0 + %t11 = load i32, ptr %t10 + %t12 = icmp eq i32 %t11, 3 + %t13 = zext i1 %t12 to i32 + %t14 = icmp ne i32 %t13, 0 + %t15 = zext i1 %t14 to i32 + store i32 %t15, ptr %t8 + br i1 %t14, label %sc0, label %scend1 +sc0: + %t16 = load ptr, ptr %t7 + %t17 = getelementptr inbounds %Str_Tok, ptr %t16, i32 0, i32 1 + %t18 = load ptr, ptr %t17 + %t19 = load ptr, ptr %t0 + %t20 = call i32 @fn_streq(ptr %t18, ptr %t19) + %t21 = icmp ne i32 %t20, 0 + %t22 = zext i1 %t21 to i32 + store i32 %t22, ptr %t8 + br label %scend1 +scend1: + %t23 = load i32, ptr %t8 + store i32 %t23, ptr %retval + br label %ret +ret: + %t24 = load i32, ptr %retval + ret i32 %t24 +} + +define i32 @fn_is_id(ptr %arg_v) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t7 = alloca ptr + %t8 = alloca i32 + store ptr %arg_v, ptr %t0 + %t1 = load ptr, ptr @g_toks + %t2 = getelementptr inbounds %LSlice, ptr %t1, i32 0, i32 0 + %t3 = load ptr, ptr %t2 + %t4 = load i32, ptr @g_pi + %t5 = getelementptr inbounds ptr, ptr %t3, i32 %t4 + %t6 = load ptr, ptr %t5 + store ptr %t6, ptr %t7 + %t9 = load ptr, ptr %t7 + %t10 = getelementptr inbounds %Str_Tok, ptr %t9, i32 0, i32 0 + %t11 = load i32, ptr %t10 + %t12 = icmp eq i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + %t14 = icmp ne i32 %t13, 0 + %t15 = zext i1 %t14 to i32 + store i32 %t15, ptr %t8 + br i1 %t14, label %sc0, label %scend1 +sc0: + %t16 = load ptr, ptr %t7 + %t17 = getelementptr inbounds %Str_Tok, ptr %t16, i32 0, i32 1 + %t18 = load ptr, ptr %t17 + %t19 = load ptr, ptr %t0 + %t20 = call i32 @fn_streq(ptr %t18, ptr %t19) + %t21 = icmp ne i32 %t20, 0 + %t22 = zext i1 %t21 to i32 + store i32 %t22, ptr %t8 + br label %scend1 +scend1: + %t23 = load i32, ptr %t8 + store i32 %t23, ptr %retval + br label %ret +ret: + %t24 = load i32, ptr %retval + ret i32 %t24 +} + +define i32 @fn_is_kw(ptr %arg_v) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + store ptr %arg_v, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_is_id(ptr %t1) + store i32 %t2, ptr %retval + br label %ret +ret: + %t3 = load i32, ptr %retval + ret i32 %t3 +} + +define void @fn_perr(ptr %arg_msg) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + store ptr %arg_msg, ptr %t0 + %t1 = load ptr, ptr @__stderrp + store ptr %t1, ptr %t2 + %t3 = load ptr, ptr %t2 + %t4 = zext i32 27 to i64 + %t5 = call i64 @fwrite(ptr @.str1, i64 1, i64 %t4, ptr %t3) + %t6 = trunc i64 %t5 to i32 + %t7 = load ptr, ptr %t2 + %t8 = load ptr, ptr %t0 + %t9 = load ptr, ptr %t0 + %t10 = call i32 @fn_slen(ptr %t9) + %t11 = zext i32 %t10 to i64 + %t12 = call i64 @fwrite(ptr %t8, i64 1, i64 %t11, ptr %t7) + %t13 = trunc i64 %t12 to i32 + %t14 = load ptr, ptr %t2 + %t15 = zext i32 1 to i64 + %t16 = call i64 @fwrite(ptr @.str2, i64 1, i64 %t15, ptr %t14) + %t17 = trunc i64 %t16 to i32 + call void @exit(i32 1) + unreachable +ret: + ret void +} + +define void @fn_eat_op(ptr %arg_v) { +entry: + %t0 = alloca ptr + store ptr %arg_v, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_is_op(ptr %t1) + %t3 = icmp eq i32 %t2, 0 + %t4 = zext i1 %t3 to i32 + %t5 = icmp ne i32 %t4, 0 + br i1 %t5, label %then0, label %ifend2 +then0: + %t6 = load ptr, ptr %t0 + call void @fn_perr(ptr %t6) + br label %ifend2 +ifend2: + %t7 = load i32, ptr @g_pi + %t8 = add i32 %t7, 1 + store i32 %t8, ptr @g_pi + br label %ret +ret: + ret void +} + +define ptr @fn_eat_id() { +entry: + %retval = alloca ptr + %t6 = alloca ptr + %t0 = load ptr, ptr @g_toks + %t1 = getelementptr inbounds %LSlice, ptr %t0, i32 0, i32 0 + %t2 = load ptr, ptr %t1 + %t3 = load i32, ptr @g_pi + %t4 = getelementptr inbounds ptr, ptr %t2, i32 %t3 + %t5 = load ptr, ptr %t4 + store ptr %t5, ptr %t6 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %Str_Tok, ptr %t7, i32 0, i32 0 + %t9 = load i32, ptr %t8 + %t10 = icmp ne i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %ifend2 +then0: + call void @fn_perr(ptr @.str3) + br label %ifend2 +ifend2: + %t13 = load i32, ptr @g_pi + %t14 = add i32 %t13, 1 + store i32 %t14, ptr @g_pi + %t15 = load ptr, ptr %t6 + %t16 = getelementptr inbounds %Str_Tok, ptr %t15, i32 0, i32 1 + %t17 = load ptr, ptr %t16 + store ptr %t17, ptr %retval + br label %ret +ret: + %t18 = load ptr, ptr %retval + ret ptr %t18 +} + +define void @fn_skipnl() { +entry: + br label %wcond0 +wcond0: + %t0 = load ptr, ptr @g_toks + %t1 = getelementptr inbounds %LSlice, ptr %t0, i32 0, i32 0 + %t2 = load ptr, ptr %t1 + %t3 = load i32, ptr @g_pi + %t4 = getelementptr inbounds ptr, ptr %t2, i32 %t3 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds %Str_Tok, ptr %t5, i32 0, i32 0 + %t7 = load i32, ptr %t6 + %t8 = icmp eq i32 %t7, 4 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t11 = load i32, ptr @g_pi + %t12 = add i32 %t11, 1 + store i32 %t12, ptr @g_pi + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define ptr @fn_ptype() { +entry: + %retval = alloca ptr + %t5 = alloca ptr + %t11 = alloca ptr + %t18 = alloca i32 + %t0 = call i32 @fn_is_op(ptr @.str4) + %t1 = icmp ne i32 %t0, 0 + br i1 %t1, label %then0, label %ifend2 +then0: + %t2 = load i32, ptr @g_pi + %t3 = add i32 %t2, 1 + store i32 %t3, ptr @g_pi + call void @fn_eat_op(ptr @.str5) + %t4 = call ptr @fn_ptype() + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = call i32 @fn_slen(ptr %t6) + %t8 = add i32 %t7, 3 + %t9 = zext i32 %t8 to i64 + %t10 = call ptr @malloc(i64 %t9) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds i8, ptr %t12, i32 0 + %t14 = trunc i32 91 to i8 + store i8 %t14, ptr %t13 + %t15 = load ptr, ptr %t11 + %t16 = getelementptr inbounds i8, ptr %t15, i32 1 + %t17 = trunc i32 93 to i8 + store i8 %t17, ptr %t16 + store i32 0, ptr %t18 + br label %wcond3 +wcond3: + %t19 = load ptr, ptr %t5 + %t20 = load i32, ptr %t18 + %t21 = getelementptr inbounds i8, ptr %t19, i32 %t20 + %t22 = load i8, ptr %t21 + %t23 = zext i8 %t22 to i32 + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %wbody4, label %wend5 +wbody4: + %t27 = load ptr, ptr %t11 + %t28 = load i32, ptr %t18 + %t29 = add i32 2, %t28 + %t30 = load ptr, ptr %t5 + %t31 = load i32, ptr %t18 + %t32 = getelementptr inbounds i8, ptr %t30, i32 %t31 + %t33 = load i8, ptr %t32 + %t34 = zext i8 %t33 to i32 + %t35 = getelementptr inbounds i8, ptr %t27, i32 %t29 + %t36 = trunc i32 %t34 to i8 + store i8 %t36, ptr %t35 + %t37 = load i32, ptr %t18 + %t38 = add i32 %t37, 1 + store i32 %t38, ptr %t18 + br label %wcond3 +wend5: + %t39 = load ptr, ptr %t11 + %t40 = load i32, ptr %t18 + %t41 = add i32 2, %t40 + %t42 = getelementptr inbounds i8, ptr %t39, i32 %t41 + %t43 = trunc i32 0 to i8 + store i8 %t43, ptr %t42 + %t44 = load ptr, ptr %t11 + store ptr %t44, ptr %retval + br label %ret +ifend2: + %t45 = call ptr @fn_eat_id() + store ptr %t45, ptr %retval + br label %ret +ret: + %t46 = load ptr, ptr %retval + ret ptr %t46 +} + +define ptr @fn_expr() { +entry: + %retval = alloca ptr + %t0 = call ptr @fn_p_or() + store ptr %t0, ptr %retval + br label %ret +ret: + %t1 = load ptr, ptr %retval + ret ptr %t1 +} + +define void @fn_args_call(ptr %arg_call) { +entry: + %t0 = alloca ptr + store ptr %arg_call, ptr %t0 + call void @fn_eat_op(ptr @.str6) + call void @fn_skipnl() + br label %wcond0 +wcond0: + %t1 = call i32 @fn_is_op(ptr @.str7) + %t2 = icmp eq i32 %t1, 0 + %t3 = zext i1 %t2 to i32 + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %wbody1, label %wend2 +wbody1: + %t5 = load ptr, ptr %t0 + %t6 = getelementptr inbounds %Str_Node, ptr %t5, i32 0, i32 7 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 1 + %t9 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 2 + %t10 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 0 + %t11 = load i32, ptr %t8 + %t12 = load i32, ptr %t9 + %t13 = icmp sge i32 %t11, %t12 + br i1 %t13, label %grow3, label %put4 +grow3: + %t14 = mul i32 %t12, 2 + %t15 = icmp eq i32 %t12, 0 + %t16 = select i1 %t15, i32 8, i32 %t14 + %t17 = getelementptr ptr, ptr null, i32 1 + %t18 = ptrtoint ptr %t17 to i64 + %t19 = zext i32 %t16 to i64 + %t20 = mul i64 %t19, %t18 + %t21 = load ptr, ptr %t10 + %t22 = call ptr @realloc(ptr %t21, i64 %t20) + store ptr %t22, ptr %t10 + store i32 %t16, ptr %t9 + br label %put4 +put4: + %t23 = call ptr @fn_expr() + %t24 = load ptr, ptr %t10 + %t25 = getelementptr inbounds ptr, ptr %t24, i32 %t11 + store ptr %t23, ptr %t25 + %t26 = add i32 %t11, 1 + store i32 %t26, ptr %t8 + call void @fn_skipnl() + %t27 = call i32 @fn_is_op(ptr @.str8) + %t28 = icmp ne i32 %t27, 0 + br i1 %t28, label %then5, label %ifend7 +then5: + %t29 = load i32, ptr @g_pi + %t30 = add i32 %t29, 1 + store i32 %t30, ptr @g_pi + call void @fn_skipnl() + br label %ifend7 +ifend7: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str9) + br label %ret +ret: + ret void +} + +define ptr @fn_p_primary() { +entry: + %retval = alloca ptr + %t6 = alloca ptr + %t14 = alloca ptr + %t30 = alloca ptr + %t46 = alloca ptr + %t67 = alloca ptr + %t79 = alloca ptr + %t93 = alloca ptr + %t99 = alloca ptr + %t113 = alloca ptr + %t0 = load ptr, ptr @g_toks + %t1 = getelementptr inbounds %LSlice, ptr %t0, i32 0, i32 0 + %t2 = load ptr, ptr %t1 + %t3 = load i32, ptr @g_pi + %t4 = getelementptr inbounds ptr, ptr %t2, i32 %t3 + %t5 = load ptr, ptr %t4 + store ptr %t5, ptr %t6 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %Str_Tok, ptr %t7, i32 0, i32 0 + %t9 = load i32, ptr %t8 + %t10 = icmp eq i32 %t9, 1 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %ifend2 +then0: + %t13 = call ptr @fn_node(i32 30) + store ptr %t13, ptr %t14 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 2 + %t17 = load ptr, ptr %t6 + %t18 = getelementptr inbounds %Str_Tok, ptr %t17, i32 0, i32 2 + %t19 = load i32, ptr %t18 + store i32 %t19, ptr %t16 + %t20 = load i32, ptr @g_pi + %t21 = add i32 %t20, 1 + store i32 %t21, ptr @g_pi + %t22 = load ptr, ptr %t14 + store ptr %t22, ptr %retval + br label %ret +ifend2: + %t23 = load ptr, ptr %t6 + %t24 = getelementptr inbounds %Str_Tok, ptr %t23, i32 0, i32 0 + %t25 = load i32, ptr %t24 + %t26 = icmp eq i32 %t25, 6 + %t27 = zext i1 %t26 to i32 + %t28 = icmp ne i32 %t27, 0 + br i1 %t28, label %then3, label %ifend5 +then3: + %t29 = call ptr @fn_node(i32 40) + store ptr %t29, ptr %t30 + %t31 = load ptr, ptr %t30 + %t32 = getelementptr inbounds %Str_Node, ptr %t31, i32 0, i32 2 + %t33 = load ptr, ptr %t6 + %t34 = getelementptr inbounds %Str_Tok, ptr %t33, i32 0, i32 2 + %t35 = load i32, ptr %t34 + store i32 %t35, ptr %t32 + %t36 = load i32, ptr @g_pi + %t37 = add i32 %t36, 1 + store i32 %t37, ptr @g_pi + %t38 = load ptr, ptr %t30 + store ptr %t38, ptr %retval + br label %ret +ifend5: + %t39 = load ptr, ptr %t6 + %t40 = getelementptr inbounds %Str_Tok, ptr %t39, i32 0, i32 0 + %t41 = load i32, ptr %t40 + %t42 = icmp eq i32 %t41, 2 + %t43 = zext i1 %t42 to i32 + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then6, label %ifend8 +then6: + %t45 = call ptr @fn_node(i32 31) + store ptr %t45, ptr %t46 + %t47 = load ptr, ptr %t46 + %t48 = getelementptr inbounds %Str_Node, ptr %t47, i32 0, i32 1 + %t49 = load ptr, ptr %t6 + %t50 = getelementptr inbounds %Str_Tok, ptr %t49, i32 0, i32 1 + %t51 = load ptr, ptr %t50 + store ptr %t51, ptr %t48 + %t52 = load i32, ptr @g_pi + %t53 = add i32 %t52, 1 + store i32 %t53, ptr @g_pi + %t54 = load ptr, ptr %t46 + store ptr %t54, ptr %retval + br label %ret +ifend8: + %t55 = load ptr, ptr %t6 + %t56 = getelementptr inbounds %Str_Tok, ptr %t55, i32 0, i32 0 + %t57 = load i32, ptr %t56 + %t58 = icmp eq i32 %t57, 0 + %t59 = zext i1 %t58 to i32 + %t60 = icmp ne i32 %t59, 0 + br i1 %t60, label %then9, label %ifend11 +then9: + %t61 = load ptr, ptr %t6 + %t62 = getelementptr inbounds %Str_Tok, ptr %t61, i32 0, i32 1 + %t63 = load ptr, ptr %t62 + %t64 = call i32 @fn_streq(ptr %t63, ptr @.str10) + %t65 = icmp ne i32 %t64, 0 + br i1 %t65, label %then12, label %ifend14 +then12: + %t66 = call ptr @fn_node(i32 32) + store ptr %t66, ptr %t67 + %t68 = load ptr, ptr %t67 + %t69 = getelementptr inbounds %Str_Node, ptr %t68, i32 0, i32 2 + store i32 1, ptr %t69 + %t70 = load i32, ptr @g_pi + %t71 = add i32 %t70, 1 + store i32 %t71, ptr @g_pi + %t72 = load ptr, ptr %t67 + store ptr %t72, ptr %retval + br label %ret +ifend14: + %t73 = load ptr, ptr %t6 + %t74 = getelementptr inbounds %Str_Tok, ptr %t73, i32 0, i32 1 + %t75 = load ptr, ptr %t74 + %t76 = call i32 @fn_streq(ptr %t75, ptr @.str11) + %t77 = icmp ne i32 %t76, 0 + br i1 %t77, label %then15, label %ifend17 +then15: + %t78 = call ptr @fn_node(i32 32) + store ptr %t78, ptr %t79 + %t80 = load ptr, ptr %t79 + %t81 = getelementptr inbounds %Str_Node, ptr %t80, i32 0, i32 2 + store i32 0, ptr %t81 + %t82 = load i32, ptr @g_pi + %t83 = add i32 %t82, 1 + store i32 %t83, ptr @g_pi + %t84 = load ptr, ptr %t79 + store ptr %t84, ptr %retval + br label %ret +ifend17: + %t85 = load ptr, ptr %t6 + %t86 = getelementptr inbounds %Str_Tok, ptr %t85, i32 0, i32 1 + %t87 = load ptr, ptr %t86 + %t88 = call i32 @fn_streq(ptr %t87, ptr @.str12) + %t89 = icmp ne i32 %t88, 0 + br i1 %t89, label %then18, label %ifend20 +then18: + %t90 = load i32, ptr @g_pi + %t91 = add i32 %t90, 1 + store i32 %t91, ptr @g_pi + %t92 = call ptr @fn_node(i32 39) + store ptr %t92, ptr %t93 + %t94 = load ptr, ptr %t93 + %t95 = getelementptr inbounds %Str_Node, ptr %t94, i32 0, i32 1 + %t96 = call ptr @fn_ptype() + store ptr %t96, ptr %t95 + %t97 = load ptr, ptr %t93 + store ptr %t97, ptr %retval + br label %ret +ifend20: + %t98 = call ptr @fn_node(i32 33) + store ptr %t98, ptr %t99 + %t100 = load ptr, ptr %t99 + %t101 = getelementptr inbounds %Str_Node, ptr %t100, i32 0, i32 1 + %t102 = load ptr, ptr %t6 + %t103 = getelementptr inbounds %Str_Tok, ptr %t102, i32 0, i32 1 + %t104 = load ptr, ptr %t103 + store ptr %t104, ptr %t101 + %t105 = load i32, ptr @g_pi + %t106 = add i32 %t105, 1 + store i32 %t106, ptr @g_pi + %t107 = load ptr, ptr %t99 + store ptr %t107, ptr %retval + br label %ret +ifend11: + %t108 = call i32 @fn_is_op(ptr @.str13) + %t109 = icmp ne i32 %t108, 0 + br i1 %t109, label %then21, label %ifend23 +then21: + %t110 = load i32, ptr @g_pi + %t111 = add i32 %t110, 1 + store i32 %t111, ptr @g_pi + call void @fn_skipnl() + %t112 = call ptr @fn_expr() + store ptr %t112, ptr %t113 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str14) + %t114 = load ptr, ptr %t113 + store ptr %t114, ptr %retval + br label %ret +ifend23: + call void @fn_perr(ptr @.str15) + %t115 = call ptr @fn_node(i32 30) + store ptr %t115, ptr %retval + br label %ret +ret: + %t116 = load ptr, ptr %retval + ret ptr %t116 +} + +define ptr @fn_p_postfix() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t8 = alloca ptr + %t21 = alloca ptr + %t32 = alloca ptr + %t0 = call ptr @fn_p_primary() + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = icmp ne i32 1, 0 + br i1 %t2, label %wbody1, label %wend2 +wbody1: + %t3 = call i32 @fn_is_op(ptr @.str16) + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then3, label %else4 +then3: + %t5 = load i32, ptr @g_pi + %t6 = add i32 %t5, 1 + store i32 %t6, ptr @g_pi + %t7 = call ptr @fn_node(i32 35) + store ptr %t7, ptr %t8 + %t9 = load ptr, ptr %t8 + %t10 = getelementptr inbounds %Str_Node, ptr %t9, i32 0, i32 4 + %t11 = load ptr, ptr %t1 + store ptr %t11, ptr %t10 + %t12 = load ptr, ptr %t8 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = call ptr @fn_eat_id() + store ptr %t14, ptr %t13 + %t15 = load ptr, ptr %t8 + store ptr %t15, ptr %t1 + br label %ifend5 +else4: + %t16 = call i32 @fn_is_op(ptr @.str17) + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %then6, label %else7 +then6: + %t18 = load i32, ptr @g_pi + %t19 = add i32 %t18, 1 + store i32 %t19, ptr @g_pi + %t20 = call ptr @fn_node(i32 36) + store ptr %t20, ptr %t21 + %t22 = load ptr, ptr %t21 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 4 + %t24 = load ptr, ptr %t1 + store ptr %t24, ptr %t23 + %t25 = load ptr, ptr %t21 + %t26 = getelementptr inbounds %Str_Node, ptr %t25, i32 0, i32 5 + %t27 = call ptr @fn_expr() + store ptr %t27, ptr %t26 + call void @fn_eat_op(ptr @.str18) + %t28 = load ptr, ptr %t21 + store ptr %t28, ptr %t1 + br label %ifend8 +else7: + %t29 = call i32 @fn_is_op(ptr @.str19) + %t30 = icmp ne i32 %t29, 0 + br i1 %t30, label %then9, label %else10 +then9: + %t31 = call ptr @fn_node(i32 34) + store ptr %t31, ptr %t32 + %t33 = load ptr, ptr %t32 + %t34 = getelementptr inbounds %Str_Node, ptr %t33, i32 0, i32 4 + %t35 = load ptr, ptr %t1 + store ptr %t35, ptr %t34 + %t36 = load ptr, ptr %t32 + call void @fn_args_call(ptr %t36) + %t37 = load ptr, ptr %t32 + store ptr %t37, ptr %t1 + br label %ifend11 +else10: + br label %wend2 +ifend11: + br label %ifend8 +ifend8: + br label %ifend5 +ifend5: + br label %wcond0 +wend2: + %t38 = load ptr, ptr %t1 + store ptr %t38, ptr %retval + br label %ret +ret: + %t39 = load ptr, ptr %retval + ret ptr %t39 +} + +define ptr @fn_p_unary() { +entry: + %retval = alloca ptr + %t5 = alloca ptr + %t17 = alloca ptr + %t0 = call i32 @fn_is_op(ptr @.str20) + %t1 = icmp ne i32 %t0, 0 + br i1 %t1, label %then0, label %ifend2 +then0: + %t2 = load i32, ptr @g_pi + %t3 = add i32 %t2, 1 + store i32 %t3, ptr @g_pi + %t4 = call ptr @fn_node(i32 38) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Node, ptr %t6, i32 0, i32 1 + store ptr @.str21, ptr %t7 + %t8 = load ptr, ptr %t5 + %t9 = getelementptr inbounds %Str_Node, ptr %t8, i32 0, i32 4 + %t10 = call ptr @fn_p_unary() + store ptr %t10, ptr %t9 + %t11 = load ptr, ptr %t5 + store ptr %t11, ptr %retval + br label %ret +ifend2: + %t12 = call i32 @fn_is_id(ptr @.str22) + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then3, label %ifend5 +then3: + %t14 = load i32, ptr @g_pi + %t15 = add i32 %t14, 1 + store i32 %t15, ptr @g_pi + %t16 = call ptr @fn_node(i32 38) + store ptr %t16, ptr %t17 + %t18 = load ptr, ptr %t17 + %t19 = getelementptr inbounds %Str_Node, ptr %t18, i32 0, i32 1 + store ptr @.str23, ptr %t19 + %t20 = load ptr, ptr %t17 + %t21 = getelementptr inbounds %Str_Node, ptr %t20, i32 0, i32 4 + %t22 = call ptr @fn_p_unary() + store ptr %t22, ptr %t21 + %t23 = load ptr, ptr %t17 + store ptr %t23, ptr %retval + br label %ret +ifend5: + %t24 = call ptr @fn_p_postfix() + store ptr %t24, ptr %retval + br label %ret +ret: + %t25 = load ptr, ptr %retval + ret ptr %t25 +} + +define ptr @fn_mkbin(ptr %arg_op, ptr %arg_l, ptr %arg_r) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca ptr + %t4 = alloca ptr + store ptr %arg_op, ptr %t0 + store ptr %arg_l, ptr %t1 + store ptr %arg_r, ptr %t2 + %t3 = call ptr @fn_node(i32 37) + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds %Str_Node, ptr %t5, i32 0, i32 1 + %t7 = load ptr, ptr %t0 + store ptr %t7, ptr %t6 + %t8 = load ptr, ptr %t4 + %t9 = getelementptr inbounds %Str_Node, ptr %t8, i32 0, i32 4 + %t10 = load ptr, ptr %t1 + store ptr %t10, ptr %t9 + %t11 = load ptr, ptr %t4 + %t12 = getelementptr inbounds %Str_Node, ptr %t11, i32 0, i32 5 + %t13 = load ptr, ptr %t2 + store ptr %t13, ptr %t12 + %t14 = load ptr, ptr %t4 + store ptr %t14, ptr %retval + br label %ret +ret: + %t15 = load ptr, ptr %retval + ret ptr %t15 +} + +define ptr @fn_p_mul() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + %t3 = alloca i32 + %t26 = alloca ptr + %t0 = call ptr @fn_p_unary() + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t4 = call i32 @fn_is_op(ptr @.str24) + %t5 = icmp ne i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %t3 + br i1 %t5, label %scend4, label %sc3 +sc3: + %t7 = call i32 @fn_is_op(ptr @.str25) + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t3 + br label %scend4 +scend4: + %t10 = load i32, ptr %t3 + %t11 = icmp ne i32 %t10, 0 + %t12 = zext i1 %t11 to i32 + store i32 %t12, ptr %t2 + br i1 %t11, label %scend6, label %sc5 +sc5: + %t13 = call i32 @fn_is_op(ptr @.str26) + %t14 = icmp ne i32 %t13, 0 + %t15 = zext i1 %t14 to i32 + store i32 %t15, ptr %t2 + br label %scend6 +scend6: + %t16 = load i32, ptr %t2 + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %wbody1, label %wend2 +wbody1: + %t18 = load ptr, ptr @g_toks + %t19 = getelementptr inbounds %LSlice, ptr %t18, i32 0, i32 0 + %t20 = load ptr, ptr %t19 + %t21 = load i32, ptr @g_pi + %t22 = getelementptr inbounds ptr, ptr %t20, i32 %t21 + %t23 = load ptr, ptr %t22 + %t24 = getelementptr inbounds %Str_Tok, ptr %t23, i32 0, i32 1 + %t25 = load ptr, ptr %t24 + store ptr %t25, ptr %t26 + %t27 = load i32, ptr @g_pi + %t28 = add i32 %t27, 1 + store i32 %t28, ptr @g_pi + %t29 = load ptr, ptr %t26 + %t30 = load ptr, ptr %t1 + %t31 = call ptr @fn_p_unary() + %t32 = call ptr @fn_mkbin(ptr %t29, ptr %t30, ptr %t31) + store ptr %t32, ptr %t1 + br label %wcond0 +wend2: + %t33 = load ptr, ptr %t1 + store ptr %t33, ptr %retval + br label %ret +ret: + %t34 = load ptr, ptr %retval + ret ptr %t34 +} + +define ptr @fn_p_add() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + %t19 = alloca ptr + %t0 = call ptr @fn_p_mul() + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t3 = call i32 @fn_is_op(ptr @.str27) + %t4 = icmp ne i32 %t3, 0 + %t5 = zext i1 %t4 to i32 + store i32 %t5, ptr %t2 + br i1 %t4, label %scend4, label %sc3 +sc3: + %t6 = call i32 @fn_is_op(ptr @.str28) + %t7 = icmp ne i32 %t6, 0 + %t8 = zext i1 %t7 to i32 + store i32 %t8, ptr %t2 + br label %scend4 +scend4: + %t9 = load i32, ptr %t2 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t11 = load ptr, ptr @g_toks + %t12 = getelementptr inbounds %LSlice, ptr %t11, i32 0, i32 0 + %t13 = load ptr, ptr %t12 + %t14 = load i32, ptr @g_pi + %t15 = getelementptr inbounds ptr, ptr %t13, i32 %t14 + %t16 = load ptr, ptr %t15 + %t17 = getelementptr inbounds %Str_Tok, ptr %t16, i32 0, i32 1 + %t18 = load ptr, ptr %t17 + store ptr %t18, ptr %t19 + %t20 = load i32, ptr @g_pi + %t21 = add i32 %t20, 1 + store i32 %t21, ptr @g_pi + %t22 = load ptr, ptr %t19 + %t23 = load ptr, ptr %t1 + %t24 = call ptr @fn_p_mul() + %t25 = call ptr @fn_mkbin(ptr %t22, ptr %t23, ptr %t24) + store ptr %t25, ptr %t1 + br label %wcond0 +wend2: + %t26 = load ptr, ptr %t1 + store ptr %t26, ptr %retval + br label %ret +ret: + %t27 = load ptr, ptr %retval + ret ptr %t27 +} + +define ptr @fn_p_cmp() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + %t3 = alloca i32 + %t4 = alloca i32 + %t5 = alloca i32 + %t6 = alloca i32 + %t47 = alloca ptr + %t0 = call ptr @fn_p_add() + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t7 = call i32 @fn_is_op(ptr @.str29) + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t6 + br i1 %t8, label %scend4, label %sc3 +sc3: + %t10 = call i32 @fn_is_op(ptr @.str30) + %t11 = icmp ne i32 %t10, 0 + %t12 = zext i1 %t11 to i32 + store i32 %t12, ptr %t6 + br label %scend4 +scend4: + %t13 = load i32, ptr %t6 + %t14 = icmp ne i32 %t13, 0 + %t15 = zext i1 %t14 to i32 + store i32 %t15, ptr %t5 + br i1 %t14, label %scend6, label %sc5 +sc5: + %t16 = call i32 @fn_is_op(ptr @.str31) + %t17 = icmp ne i32 %t16, 0 + %t18 = zext i1 %t17 to i32 + store i32 %t18, ptr %t5 + br label %scend6 +scend6: + %t19 = load i32, ptr %t5 + %t20 = icmp ne i32 %t19, 0 + %t21 = zext i1 %t20 to i32 + store i32 %t21, ptr %t4 + br i1 %t20, label %scend8, label %sc7 +sc7: + %t22 = call i32 @fn_is_op(ptr @.str32) + %t23 = icmp ne i32 %t22, 0 + %t24 = zext i1 %t23 to i32 + store i32 %t24, ptr %t4 + br label %scend8 +scend8: + %t25 = load i32, ptr %t4 + %t26 = icmp ne i32 %t25, 0 + %t27 = zext i1 %t26 to i32 + store i32 %t27, ptr %t3 + br i1 %t26, label %scend10, label %sc9 +sc9: + %t28 = call i32 @fn_is_op(ptr @.str33) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t3 + br label %scend10 +scend10: + %t31 = load i32, ptr %t3 + %t32 = icmp ne i32 %t31, 0 + %t33 = zext i1 %t32 to i32 + store i32 %t33, ptr %t2 + br i1 %t32, label %scend12, label %sc11 +sc11: + %t34 = call i32 @fn_is_op(ptr @.str34) + %t35 = icmp ne i32 %t34, 0 + %t36 = zext i1 %t35 to i32 + store i32 %t36, ptr %t2 + br label %scend12 +scend12: + %t37 = load i32, ptr %t2 + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %wbody1, label %wend2 +wbody1: + %t39 = load ptr, ptr @g_toks + %t40 = getelementptr inbounds %LSlice, ptr %t39, i32 0, i32 0 + %t41 = load ptr, ptr %t40 + %t42 = load i32, ptr @g_pi + %t43 = getelementptr inbounds ptr, ptr %t41, i32 %t42 + %t44 = load ptr, ptr %t43 + %t45 = getelementptr inbounds %Str_Tok, ptr %t44, i32 0, i32 1 + %t46 = load ptr, ptr %t45 + store ptr %t46, ptr %t47 + %t48 = load i32, ptr @g_pi + %t49 = add i32 %t48, 1 + store i32 %t49, ptr @g_pi + %t50 = load ptr, ptr %t47 + %t51 = load ptr, ptr %t1 + %t52 = call ptr @fn_p_add() + %t53 = call ptr @fn_mkbin(ptr %t50, ptr %t51, ptr %t52) + store ptr %t53, ptr %t1 + br label %wcond0 +wend2: + %t54 = load ptr, ptr %t1 + store ptr %t54, ptr %retval + br label %ret +ret: + %t55 = load ptr, ptr %retval + ret ptr %t55 +} + +define ptr @fn_p_and() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t0 = call ptr @fn_p_cmp() + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = call i32 @fn_is_id(ptr @.str35) + %t3 = icmp ne i32 %t2, 0 + br i1 %t3, label %wbody1, label %wend2 +wbody1: + %t4 = load i32, ptr @g_pi + %t5 = add i32 %t4, 1 + store i32 %t5, ptr @g_pi + %t6 = load ptr, ptr %t1 + %t7 = call ptr @fn_p_cmp() + %t8 = call ptr @fn_mkbin(ptr @.str36, ptr %t6, ptr %t7) + store ptr %t8, ptr %t1 + br label %wcond0 +wend2: + %t9 = load ptr, ptr %t1 + store ptr %t9, ptr %retval + br label %ret +ret: + %t10 = load ptr, ptr %retval + ret ptr %t10 +} + +define ptr @fn_p_or() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t0 = call ptr @fn_p_and() + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = call i32 @fn_is_id(ptr @.str37) + %t3 = icmp ne i32 %t2, 0 + br i1 %t3, label %wbody1, label %wend2 +wbody1: + %t4 = load i32, ptr @g_pi + %t5 = add i32 %t4, 1 + store i32 %t5, ptr @g_pi + %t6 = load ptr, ptr %t1 + %t7 = call ptr @fn_p_and() + %t8 = call ptr @fn_mkbin(ptr @.str38, ptr %t6, ptr %t7) + store ptr %t8, ptr %t1 + br label %wcond0 +wend2: + %t9 = load ptr, ptr %t1 + store ptr %t9, ptr %retval + br label %ret +ret: + %t10 = load ptr, ptr %retval + ret ptr %t10 +} + +define ptr @fn_record() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t6 = alloca ptr + call void @fn_eat_op(ptr @.str39) + %t0 = call ptr @fn_node(i32 41) + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = icmp ne i32 1, 0 + br i1 %t2, label %wbody1, label %wend2 +wbody1: + call void @fn_skipnl() + %t3 = call i32 @fn_is_op(ptr @.str40) + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then3, label %ifend5 +then3: + br label %wend2 +ifend5: + %t5 = call ptr @fn_node(i32 42) + store ptr %t5, ptr %t6 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 1 + %t9 = call ptr @fn_eat_id() + store ptr %t9, ptr %t8 + call void @fn_eat_op(ptr @.str41) + %t10 = load ptr, ptr %t6 + %t11 = getelementptr inbounds %Str_Node, ptr %t10, i32 0, i32 4 + %t12 = call ptr @fn_expr() + store ptr %t12, ptr %t11 + %t13 = load ptr, ptr %t1 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 7 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %LSlice, ptr %t15, i32 0, i32 1 + %t17 = getelementptr inbounds %LSlice, ptr %t15, i32 0, i32 2 + %t18 = getelementptr inbounds %LSlice, ptr %t15, i32 0, i32 0 + %t19 = load i32, ptr %t16 + %t20 = load i32, ptr %t17 + %t21 = icmp sge i32 %t19, %t20 + br i1 %t21, label %grow6, label %put7 +grow6: + %t22 = mul i32 %t20, 2 + %t23 = icmp eq i32 %t20, 0 + %t24 = select i1 %t23, i32 8, i32 %t22 + %t25 = getelementptr ptr, ptr null, i32 1 + %t26 = ptrtoint ptr %t25 to i64 + %t27 = zext i32 %t24 to i64 + %t28 = mul i64 %t27, %t26 + %t29 = load ptr, ptr %t18 + %t30 = call ptr @realloc(ptr %t29, i64 %t28) + store ptr %t30, ptr %t18 + store i32 %t24, ptr %t17 + br label %put7 +put7: + %t31 = load ptr, ptr %t6 + %t32 = load ptr, ptr %t18 + %t33 = getelementptr inbounds ptr, ptr %t32, i32 %t19 + store ptr %t31, ptr %t33 + %t34 = add i32 %t19, 1 + store i32 %t34, ptr %t16 + %t35 = call i32 @fn_is_op(ptr @.str42) + %t36 = icmp ne i32 %t35, 0 + br i1 %t36, label %then8, label %ifend10 +then8: + %t37 = load i32, ptr @g_pi + %t38 = add i32 %t37, 1 + store i32 %t38, ptr @g_pi + br label %ifend10 +ifend10: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str43) + %t39 = load ptr, ptr %t1 + store ptr %t39, ptr %retval + br label %ret +ret: + %t40 = load ptr, ptr %retval + ret ptr %t40 +} + +define ptr @fn_block() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str44) + %t0 = call ptr @fn_node(i32 7) + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = icmp ne i32 1, 0 + br i1 %t2, label %wbody1, label %wend2 +wbody1: + call void @fn_skipnl() + %t3 = call i32 @fn_is_op(ptr @.str45) + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then3, label %ifend5 +then3: + br label %wend2 +ifend5: + %t5 = load ptr, ptr %t1 + %t6 = getelementptr inbounds %Str_Node, ptr %t5, i32 0, i32 7 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 1 + %t9 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 2 + %t10 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 0 + %t11 = load i32, ptr %t8 + %t12 = load i32, ptr %t9 + %t13 = icmp sge i32 %t11, %t12 + br i1 %t13, label %grow6, label %put7 +grow6: + %t14 = mul i32 %t12, 2 + %t15 = icmp eq i32 %t12, 0 + %t16 = select i1 %t15, i32 8, i32 %t14 + %t17 = getelementptr ptr, ptr null, i32 1 + %t18 = ptrtoint ptr %t17 to i64 + %t19 = zext i32 %t16 to i64 + %t20 = mul i64 %t19, %t18 + %t21 = load ptr, ptr %t10 + %t22 = call ptr @realloc(ptr %t21, i64 %t20) + store ptr %t22, ptr %t10 + store i32 %t16, ptr %t9 + br label %put7 +put7: + %t23 = call ptr @fn_stmt() + %t24 = load ptr, ptr %t10 + %t25 = getelementptr inbounds ptr, ptr %t24, i32 %t11 + store ptr %t23, ptr %t25 + %t26 = add i32 %t11, 1 + store i32 %t26, ptr %t8 + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str46) + %t27 = load ptr, ptr %t1 + store ptr %t27, ptr %retval + br label %ret +ret: + %t28 = load ptr, ptr %retval + ret ptr %t28 +} + +define ptr @fn_stmt() { +entry: + %retval = alloca ptr + %t6 = alloca ptr + %t21 = alloca ptr + %t48 = alloca ptr + %t49 = alloca i32 + %t81 = alloca ptr + %t109 = alloca ptr + %t125 = alloca ptr + %t144 = alloca ptr + %t149 = alloca ptr + %t174 = alloca ptr + %t182 = alloca ptr + %t184 = alloca ptr + %t225 = alloca ptr + %t238 = alloca ptr + %t253 = alloca ptr + %t282 = alloca ptr + %t290 = alloca ptr + %t324 = alloca ptr + %t374 = alloca ptr + %t375 = alloca i32 + %t376 = alloca i32 + %t377 = alloca i32 + %t378 = alloca i32 + %t406 = alloca ptr + %t427 = alloca ptr + %t0 = load ptr, ptr @g_toks + %t1 = getelementptr inbounds %LSlice, ptr %t0, i32 0, i32 0 + %t2 = load ptr, ptr %t1 + %t3 = load i32, ptr @g_pi + %t4 = getelementptr inbounds ptr, ptr %t2, i32 %t3 + %t5 = load ptr, ptr %t4 + store ptr %t5, ptr %t6 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %Str_Tok, ptr %t7, i32 0, i32 0 + %t9 = load i32, ptr %t8 + %t10 = icmp eq i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %ifend2 +then0: + %t13 = load ptr, ptr %t6 + %t14 = getelementptr inbounds %Str_Tok, ptr %t13, i32 0, i32 1 + %t15 = load ptr, ptr %t14 + %t16 = call i32 @fn_streq(ptr %t15, ptr @.str47) + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %then3, label %ifend5 +then3: + %t18 = load i32, ptr @g_pi + %t19 = add i32 %t18, 1 + store i32 %t19, ptr @g_pi + %t20 = call ptr @fn_node(i32 10) + store ptr %t20, ptr %t21 + %t22 = load ptr, ptr %t21 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 1 + %t24 = call ptr @fn_eat_id() + store ptr %t24, ptr %t23 + %t25 = call i32 @fn_is_op(ptr @.str48) + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %then6, label %ifend8 +then6: + %t27 = load i32, ptr @g_pi + %t28 = add i32 %t27, 1 + store i32 %t28, ptr @g_pi + %t29 = load ptr, ptr %t21 + %t30 = getelementptr inbounds %Str_Node, ptr %t29, i32 0, i32 3 + %t31 = call ptr @fn_ptype() + store ptr %t31, ptr %t30 + br label %ifend8 +ifend8: + %t32 = call i32 @fn_is_op(ptr @.str49) + %t33 = icmp ne i32 %t32, 0 + br i1 %t33, label %then9, label %ifend11 +then9: + %t34 = load i32, ptr @g_pi + %t35 = add i32 %t34, 1 + store i32 %t35, ptr @g_pi + %t36 = load ptr, ptr %t21 + %t37 = getelementptr inbounds %Str_Node, ptr %t36, i32 0, i32 4 + %t38 = call ptr @fn_expr() + store ptr %t38, ptr %t37 + br label %ifend11 +ifend11: + %t39 = load ptr, ptr %t21 + store ptr %t39, ptr %retval + br label %ret +ifend5: + %t40 = load ptr, ptr %t6 + %t41 = getelementptr inbounds %Str_Tok, ptr %t40, i32 0, i32 1 + %t42 = load ptr, ptr %t41 + %t43 = call i32 @fn_streq(ptr %t42, ptr @.str50) + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then12, label %ifend14 +then12: + %t45 = load i32, ptr @g_pi + %t46 = add i32 %t45, 1 + store i32 %t46, ptr @g_pi + %t47 = call ptr @fn_node(i32 15) + store ptr %t47, ptr %t48 + %t50 = load ptr, ptr @g_toks + %t51 = getelementptr inbounds %LSlice, ptr %t50, i32 0, i32 0 + %t52 = load ptr, ptr %t51 + %t53 = load i32, ptr @g_pi + %t54 = getelementptr inbounds ptr, ptr %t52, i32 %t53 + %t55 = load ptr, ptr %t54 + %t56 = getelementptr inbounds %Str_Tok, ptr %t55, i32 0, i32 0 + %t57 = load i32, ptr %t56 + %t58 = icmp ne i32 %t57, 4 + %t59 = zext i1 %t58 to i32 + %t60 = icmp ne i32 %t59, 0 + %t61 = zext i1 %t60 to i32 + store i32 %t61, ptr %t49 + br i1 %t60, label %sc15, label %scend16 +sc15: + %t62 = call i32 @fn_is_op(ptr @.str51) + %t63 = icmp eq i32 %t62, 0 + %t64 = zext i1 %t63 to i32 + %t65 = icmp ne i32 %t64, 0 + %t66 = zext i1 %t65 to i32 + store i32 %t66, ptr %t49 + br label %scend16 +scend16: + %t67 = load i32, ptr %t49 + %t68 = icmp ne i32 %t67, 0 + br i1 %t68, label %then17, label %ifend19 +then17: + %t69 = load ptr, ptr %t48 + %t70 = getelementptr inbounds %Str_Node, ptr %t69, i32 0, i32 4 + %t71 = call ptr @fn_expr() + store ptr %t71, ptr %t70 + br label %ifend19 +ifend19: + %t72 = load ptr, ptr %t48 + store ptr %t72, ptr %retval + br label %ret +ifend14: + %t73 = load ptr, ptr %t6 + %t74 = getelementptr inbounds %Str_Tok, ptr %t73, i32 0, i32 1 + %t75 = load ptr, ptr %t74 + %t76 = call i32 @fn_streq(ptr %t75, ptr @.str52) + %t77 = icmp ne i32 %t76, 0 + br i1 %t77, label %then20, label %ifend22 +then20: + %t78 = load i32, ptr @g_pi + %t79 = add i32 %t78, 1 + store i32 %t79, ptr @g_pi + %t80 = call ptr @fn_node(i32 12) + store ptr %t80, ptr %t81 + %t82 = load ptr, ptr %t81 + %t83 = getelementptr inbounds %Str_Node, ptr %t82, i32 0, i32 4 + %t84 = call ptr @fn_expr() + store ptr %t84, ptr %t83 + %t85 = load ptr, ptr %t81 + %t86 = getelementptr inbounds %Str_Node, ptr %t85, i32 0, i32 5 + %t87 = call ptr @fn_block() + store ptr %t87, ptr %t86 + call void @fn_skipnl() + %t88 = call i32 @fn_is_id(ptr @.str53) + %t89 = icmp ne i32 %t88, 0 + br i1 %t89, label %then23, label %ifend25 +then23: + %t90 = load i32, ptr @g_pi + %t91 = add i32 %t90, 1 + store i32 %t91, ptr @g_pi + call void @fn_skipnl() + %t92 = call i32 @fn_is_id(ptr @.str54) + %t93 = icmp ne i32 %t92, 0 + br i1 %t93, label %then26, label %else27 +then26: + %t94 = load ptr, ptr %t81 + %t95 = getelementptr inbounds %Str_Node, ptr %t94, i32 0, i32 6 + %t96 = call ptr @fn_stmt() + store ptr %t96, ptr %t95 + br label %ifend28 +else27: + %t97 = load ptr, ptr %t81 + %t98 = getelementptr inbounds %Str_Node, ptr %t97, i32 0, i32 6 + %t99 = call ptr @fn_block() + store ptr %t99, ptr %t98 + br label %ifend28 +ifend28: + br label %ifend25 +ifend25: + %t100 = load ptr, ptr %t81 + store ptr %t100, ptr %retval + br label %ret +ifend22: + %t101 = load ptr, ptr %t6 + %t102 = getelementptr inbounds %Str_Tok, ptr %t101, i32 0, i32 1 + %t103 = load ptr, ptr %t102 + %t104 = call i32 @fn_streq(ptr %t103, ptr @.str55) + %t105 = icmp ne i32 %t104, 0 + br i1 %t105, label %then29, label %ifend31 +then29: + %t106 = load i32, ptr @g_pi + %t107 = add i32 %t106, 1 + store i32 %t107, ptr @g_pi + %t108 = call ptr @fn_node(i32 12) + store ptr %t108, ptr %t109 + %t110 = load ptr, ptr %t109 + %t111 = getelementptr inbounds %Str_Node, ptr %t110, i32 0, i32 4 + %t112 = call ptr @fn_expr() + store ptr %t112, ptr %t111 + %t113 = load ptr, ptr %t109 + %t114 = getelementptr inbounds %Str_Node, ptr %t113, i32 0, i32 5 + %t115 = call ptr @fn_block() + store ptr %t115, ptr %t114 + %t116 = load ptr, ptr %t109 + store ptr %t116, ptr %retval + br label %ret +ifend31: + %t117 = load ptr, ptr %t6 + %t118 = getelementptr inbounds %Str_Tok, ptr %t117, i32 0, i32 1 + %t119 = load ptr, ptr %t118 + %t120 = call i32 @fn_streq(ptr %t119, ptr @.str56) + %t121 = icmp ne i32 %t120, 0 + br i1 %t121, label %then32, label %ifend34 +then32: + %t122 = load i32, ptr @g_pi + %t123 = add i32 %t122, 1 + store i32 %t123, ptr @g_pi + %t124 = call ptr @fn_node(i32 13) + store ptr %t124, ptr %t125 + %t126 = load ptr, ptr %t125 + %t127 = getelementptr inbounds %Str_Node, ptr %t126, i32 0, i32 4 + %t128 = call ptr @fn_expr() + store ptr %t128, ptr %t127 + %t129 = load ptr, ptr %t125 + %t130 = getelementptr inbounds %Str_Node, ptr %t129, i32 0, i32 5 + %t131 = call ptr @fn_block() + store ptr %t131, ptr %t130 + %t132 = load ptr, ptr %t125 + store ptr %t132, ptr %retval + br label %ret +ifend34: + %t133 = load ptr, ptr %t6 + %t134 = getelementptr inbounds %Str_Tok, ptr %t133, i32 0, i32 1 + %t135 = load ptr, ptr %t134 + %t136 = call i32 @fn_streq(ptr %t135, ptr @.str57) + %t137 = icmp ne i32 %t136, 0 + br i1 %t137, label %then35, label %ifend37 +then35: + %t138 = load i32, ptr @g_pi + %t139 = add i32 %t138, 1 + store i32 %t139, ptr @g_pi + %t140 = call i32 @fn_is_op(ptr @.str58) + %t141 = icmp ne i32 %t140, 0 + br i1 %t141, label %then38, label %ifend40 +then38: + %t142 = call ptr @fn_parse_query_for() + store ptr %t142, ptr %retval + br label %ret +ifend40: + %t143 = call ptr @fn_node(i32 14) + store ptr %t143, ptr %t144 + %t145 = load ptr, ptr %t144 + %t146 = getelementptr inbounds %Str_Node, ptr %t145, i32 0, i32 1 + %t147 = call ptr @fn_eat_id() + store ptr %t147, ptr %t146 + %t148 = call ptr @fn_eat_id() + store ptr %t148, ptr %t149 + %t150 = load ptr, ptr %t144 + %t151 = getelementptr inbounds %Str_Node, ptr %t150, i32 0, i32 4 + %t152 = call ptr @fn_expr() + store ptr %t152, ptr %t151 + call void @fn_eat_op(ptr @.str59) + %t153 = load ptr, ptr %t144 + %t154 = getelementptr inbounds %Str_Node, ptr %t153, i32 0, i32 5 + %t155 = call ptr @fn_expr() + store ptr %t155, ptr %t154 + %t156 = load ptr, ptr %t144 + %t157 = getelementptr inbounds %Str_Node, ptr %t156, i32 0, i32 6 + %t158 = call ptr @fn_block() + store ptr %t158, ptr %t157 + %t159 = load ptr, ptr %t144 + store ptr %t159, ptr %retval + br label %ret +ifend37: + %t160 = load ptr, ptr %t6 + %t161 = getelementptr inbounds %Str_Tok, ptr %t160, i32 0, i32 1 + %t162 = load ptr, ptr %t161 + %t163 = call i32 @fn_streq(ptr %t162, ptr @.str60) + %t164 = icmp ne i32 %t163, 0 + br i1 %t164, label %then41, label %ifend43 +then41: + %t165 = call ptr @fn_parse_spawn() + store ptr %t165, ptr %retval + br label %ret +ifend43: + %t166 = load ptr, ptr %t6 + %t167 = getelementptr inbounds %Str_Tok, ptr %t166, i32 0, i32 1 + %t168 = load ptr, ptr %t167 + %t169 = call i32 @fn_streq(ptr %t168, ptr @.str61) + %t170 = icmp ne i32 %t169, 0 + br i1 %t170, label %then44, label %ifend46 +then44: + %t171 = load i32, ptr @g_pi + %t172 = add i32 %t171, 1 + store i32 %t172, ptr @g_pi + %t173 = call ptr @fn_node(i32 24) + store ptr %t173, ptr %t174 + %t175 = load ptr, ptr %t174 + %t176 = getelementptr inbounds %Str_Node, ptr %t175, i32 0, i32 4 + %t177 = call ptr @fn_expr() + store ptr %t177, ptr %t176 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str62) + br label %wcond47 +wcond47: + %t178 = icmp ne i32 1, 0 + br i1 %t178, label %wbody48, label %wend49 +wbody48: + call void @fn_skipnl() + %t179 = call i32 @fn_is_op(ptr @.str63) + %t180 = icmp ne i32 %t179, 0 + br i1 %t180, label %then50, label %ifend52 +then50: + br label %wend49 +ifend52: + %t181 = call ptr @fn_eat_id() + store ptr %t181, ptr %t182 + %t183 = call ptr @fn_node(i32 25) + store ptr %t183, ptr %t184 + %t185 = load ptr, ptr %t184 + %t186 = getelementptr inbounds %Str_Node, ptr %t185, i32 0, i32 1 + %t187 = call ptr @fn_eat_id() + store ptr %t187, ptr %t186 + call void @fn_eat_op(ptr @.str64) + %t188 = load ptr, ptr %t184 + %t189 = getelementptr inbounds %Str_Node, ptr %t188, i32 0, i32 5 + %t190 = call ptr @fn_expr() + store ptr %t190, ptr %t189 + call void @fn_skipnl() + %t191 = load ptr, ptr %t184 + %t192 = getelementptr inbounds %Str_Node, ptr %t191, i32 0, i32 4 + %t193 = call ptr @fn_block() + store ptr %t193, ptr %t192 + %t194 = load ptr, ptr %t174 + %t195 = getelementptr inbounds %Str_Node, ptr %t194, i32 0, i32 7 + %t196 = load ptr, ptr %t195 + %t197 = getelementptr inbounds %LSlice, ptr %t196, i32 0, i32 1 + %t198 = getelementptr inbounds %LSlice, ptr %t196, i32 0, i32 2 + %t199 = getelementptr inbounds %LSlice, ptr %t196, i32 0, i32 0 + %t200 = load i32, ptr %t197 + %t201 = load i32, ptr %t198 + %t202 = icmp sge i32 %t200, %t201 + br i1 %t202, label %grow53, label %put54 +grow53: + %t203 = mul i32 %t201, 2 + %t204 = icmp eq i32 %t201, 0 + %t205 = select i1 %t204, i32 8, i32 %t203 + %t206 = getelementptr ptr, ptr null, i32 1 + %t207 = ptrtoint ptr %t206 to i64 + %t208 = zext i32 %t205 to i64 + %t209 = mul i64 %t208, %t207 + %t210 = load ptr, ptr %t199 + %t211 = call ptr @realloc(ptr %t210, i64 %t209) + store ptr %t211, ptr %t199 + store i32 %t205, ptr %t198 + br label %put54 +put54: + %t212 = load ptr, ptr %t184 + %t213 = load ptr, ptr %t199 + %t214 = getelementptr inbounds ptr, ptr %t213, i32 %t200 + store ptr %t212, ptr %t214 + %t215 = add i32 %t200, 1 + store i32 %t215, ptr %t197 + br label %wcond47 +wend49: + call void @fn_eat_op(ptr @.str65) + %t216 = load ptr, ptr %t174 + store ptr %t216, ptr %retval + br label %ret +ifend46: + %t217 = load ptr, ptr %t6 + %t218 = getelementptr inbounds %Str_Tok, ptr %t217, i32 0, i32 1 + %t219 = load ptr, ptr %t218 + %t220 = call i32 @fn_streq(ptr %t219, ptr @.str66) + %t221 = icmp ne i32 %t220, 0 + br i1 %t221, label %then55, label %ifend57 +then55: + %t222 = load i32, ptr @g_pi + %t223 = add i32 %t222, 1 + store i32 %t223, ptr @g_pi + %t224 = call ptr @fn_node(i32 26) + store ptr %t224, ptr %t225 + %t226 = load ptr, ptr %t225 + %t227 = getelementptr inbounds %Str_Node, ptr %t226, i32 0, i32 1 + %t228 = call ptr @fn_eat_id() + store ptr %t228, ptr %t227 + %t229 = load ptr, ptr %t225 + store ptr %t229, ptr %retval + br label %ret +ifend57: + %t230 = load ptr, ptr %t6 + %t231 = getelementptr inbounds %Str_Tok, ptr %t230, i32 0, i32 1 + %t232 = load ptr, ptr %t231 + %t233 = call i32 @fn_streq(ptr %t232, ptr @.str67) + %t234 = icmp ne i32 %t233, 0 + br i1 %t234, label %then58, label %ifend60 +then58: + %t235 = load i32, ptr @g_pi + %t236 = add i32 %t235, 1 + store i32 %t236, ptr @g_pi + %t237 = call ptr @fn_node(i32 26) + store ptr %t237, ptr %t238 + %t239 = load ptr, ptr %t238 + %t240 = getelementptr inbounds %Str_Node, ptr %t239, i32 0, i32 1 + %t241 = call ptr @fn_eat_id() + store ptr %t241, ptr %t240 + %t242 = load ptr, ptr %t238 + %t243 = getelementptr inbounds %Str_Node, ptr %t242, i32 0, i32 2 + store i32 1, ptr %t243 + %t244 = load ptr, ptr %t238 + store ptr %t244, ptr %retval + br label %ret +ifend60: + %t245 = load ptr, ptr %t6 + %t246 = getelementptr inbounds %Str_Tok, ptr %t245, i32 0, i32 1 + %t247 = load ptr, ptr %t246 + %t248 = call i32 @fn_streq(ptr %t247, ptr @.str68) + %t249 = icmp ne i32 %t248, 0 + br i1 %t249, label %then61, label %ifend63 +then61: + %t250 = load i32, ptr @g_pi + %t251 = add i32 %t250, 1 + store i32 %t251, ptr @g_pi + %t252 = call ptr @fn_node(i32 23) + store ptr %t252, ptr %t253 + %t254 = load ptr, ptr %t253 + %t255 = getelementptr inbounds %Str_Node, ptr %t254, i32 0, i32 4 + %t256 = call ptr @fn_expr() + store ptr %t256, ptr %t255 + %t257 = load ptr, ptr %t253 + store ptr %t257, ptr %retval + br label %ret +ifend63: + %t258 = load ptr, ptr %t6 + %t259 = getelementptr inbounds %Str_Tok, ptr %t258, i32 0, i32 1 + %t260 = load ptr, ptr %t259 + %t261 = call i32 @fn_streq(ptr %t260, ptr @.str69) + %t262 = icmp ne i32 %t261, 0 + br i1 %t262, label %then64, label %ifend66 +then64: + %t263 = load i32, ptr @g_pi + %t264 = add i32 %t263, 1 + store i32 %t264, ptr @g_pi + %t265 = call ptr @fn_node(i32 17) + store ptr %t265, ptr %retval + br label %ret +ifend66: + %t266 = load ptr, ptr %t6 + %t267 = getelementptr inbounds %Str_Tok, ptr %t266, i32 0, i32 1 + %t268 = load ptr, ptr %t267 + %t269 = call i32 @fn_streq(ptr %t268, ptr @.str70) + %t270 = icmp ne i32 %t269, 0 + br i1 %t270, label %then67, label %ifend69 +then67: + %t271 = load i32, ptr @g_pi + %t272 = add i32 %t271, 1 + store i32 %t272, ptr @g_pi + %t273 = call ptr @fn_node(i32 18) + store ptr %t273, ptr %retval + br label %ret +ifend69: + %t274 = load ptr, ptr %t6 + %t275 = getelementptr inbounds %Str_Tok, ptr %t274, i32 0, i32 1 + %t276 = load ptr, ptr %t275 + %t277 = call i32 @fn_streq(ptr %t276, ptr @.str71) + %t278 = icmp ne i32 %t277, 0 + br i1 %t278, label %then70, label %ifend72 +then70: + %t279 = load i32, ptr @g_pi + %t280 = add i32 %t279, 1 + store i32 %t280, ptr @g_pi + %t281 = call ptr @fn_node(i32 19) + store ptr %t281, ptr %t282 + %t283 = load ptr, ptr %t282 + %t284 = getelementptr inbounds %Str_Node, ptr %t283, i32 0, i32 4 + %t285 = call ptr @fn_expr() + store ptr %t285, ptr %t284 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str72) + br label %wcond73 +wcond73: + %t286 = icmp ne i32 1, 0 + br i1 %t286, label %wbody74, label %wend75 +wbody74: + call void @fn_skipnl() + %t287 = call i32 @fn_is_op(ptr @.str73) + %t288 = icmp ne i32 %t287, 0 + br i1 %t288, label %then76, label %ifend78 +then76: + br label %wend75 +ifend78: + %t289 = call ptr @fn_node(i32 20) + store ptr %t289, ptr %t290 + br label %wcond79 +wcond79: + %t291 = icmp ne i32 1, 0 + br i1 %t291, label %wbody80, label %wend81 +wbody80: + %t292 = load ptr, ptr %t290 + %t293 = getelementptr inbounds %Str_Node, ptr %t292, i32 0, i32 7 + %t294 = load ptr, ptr %t293 + %t295 = getelementptr inbounds %LSlice, ptr %t294, i32 0, i32 1 + %t296 = getelementptr inbounds %LSlice, ptr %t294, i32 0, i32 2 + %t297 = getelementptr inbounds %LSlice, ptr %t294, i32 0, i32 0 + %t298 = load i32, ptr %t295 + %t299 = load i32, ptr %t296 + %t300 = icmp sge i32 %t298, %t299 + br i1 %t300, label %grow82, label %put83 +grow82: + %t301 = mul i32 %t299, 2 + %t302 = icmp eq i32 %t299, 0 + %t303 = select i1 %t302, i32 8, i32 %t301 + %t304 = getelementptr ptr, ptr null, i32 1 + %t305 = ptrtoint ptr %t304 to i64 + %t306 = zext i32 %t303 to i64 + %t307 = mul i64 %t306, %t305 + %t308 = load ptr, ptr %t297 + %t309 = call ptr @realloc(ptr %t308, i64 %t307) + store ptr %t309, ptr %t297 + store i32 %t303, ptr %t296 + br label %put83 +put83: + %t310 = call ptr @fn_expr() + %t311 = load ptr, ptr %t297 + %t312 = getelementptr inbounds ptr, ptr %t311, i32 %t298 + store ptr %t310, ptr %t312 + %t313 = add i32 %t298, 1 + store i32 %t313, ptr %t295 + %t314 = call i32 @fn_is_op(ptr @.str74) + %t315 = icmp ne i32 %t314, 0 + br i1 %t315, label %then84, label %ifend86 +then84: + %t316 = load i32, ptr @g_pi + %t317 = add i32 %t316, 1 + store i32 %t317, ptr @g_pi + call void @fn_skipnl() + br label %wcond79 +ifend86: + br label %wend81 +wend81: + call void @fn_eat_op(ptr @.str75) + call void @fn_skipnl() + %t318 = call i32 @fn_is_op(ptr @.str76) + %t319 = icmp ne i32 %t318, 0 + br i1 %t319, label %then87, label %else88 +then87: + %t320 = load ptr, ptr %t290 + %t321 = getelementptr inbounds %Str_Node, ptr %t320, i32 0, i32 4 + %t322 = call ptr @fn_block() + store ptr %t322, ptr %t321 + br label %ifend89 +else88: + %t323 = call ptr @fn_node(i32 7) + store ptr %t323, ptr %t324 + %t325 = load ptr, ptr %t324 + %t326 = getelementptr inbounds %Str_Node, ptr %t325, i32 0, i32 7 + %t327 = load ptr, ptr %t326 + %t328 = getelementptr inbounds %LSlice, ptr %t327, i32 0, i32 1 + %t329 = getelementptr inbounds %LSlice, ptr %t327, i32 0, i32 2 + %t330 = getelementptr inbounds %LSlice, ptr %t327, i32 0, i32 0 + %t331 = load i32, ptr %t328 + %t332 = load i32, ptr %t329 + %t333 = icmp sge i32 %t331, %t332 + br i1 %t333, label %grow90, label %put91 +grow90: + %t334 = mul i32 %t332, 2 + %t335 = icmp eq i32 %t332, 0 + %t336 = select i1 %t335, i32 8, i32 %t334 + %t337 = getelementptr ptr, ptr null, i32 1 + %t338 = ptrtoint ptr %t337 to i64 + %t339 = zext i32 %t336 to i64 + %t340 = mul i64 %t339, %t338 + %t341 = load ptr, ptr %t330 + %t342 = call ptr @realloc(ptr %t341, i64 %t340) + store ptr %t342, ptr %t330 + store i32 %t336, ptr %t329 + br label %put91 +put91: + %t343 = call ptr @fn_stmt() + %t344 = load ptr, ptr %t330 + %t345 = getelementptr inbounds ptr, ptr %t344, i32 %t331 + store ptr %t343, ptr %t345 + %t346 = add i32 %t331, 1 + store i32 %t346, ptr %t328 + %t347 = load ptr, ptr %t290 + %t348 = getelementptr inbounds %Str_Node, ptr %t347, i32 0, i32 4 + %t349 = load ptr, ptr %t324 + store ptr %t349, ptr %t348 + br label %ifend89 +ifend89: + %t350 = load ptr, ptr %t282 + %t351 = getelementptr inbounds %Str_Node, ptr %t350, i32 0, i32 7 + %t352 = load ptr, ptr %t351 + %t353 = getelementptr inbounds %LSlice, ptr %t352, i32 0, i32 1 + %t354 = getelementptr inbounds %LSlice, ptr %t352, i32 0, i32 2 + %t355 = getelementptr inbounds %LSlice, ptr %t352, i32 0, i32 0 + %t356 = load i32, ptr %t353 + %t357 = load i32, ptr %t354 + %t358 = icmp sge i32 %t356, %t357 + br i1 %t358, label %grow92, label %put93 +grow92: + %t359 = mul i32 %t357, 2 + %t360 = icmp eq i32 %t357, 0 + %t361 = select i1 %t360, i32 8, i32 %t359 + %t362 = getelementptr ptr, ptr null, i32 1 + %t363 = ptrtoint ptr %t362 to i64 + %t364 = zext i32 %t361 to i64 + %t365 = mul i64 %t364, %t363 + %t366 = load ptr, ptr %t355 + %t367 = call ptr @realloc(ptr %t366, i64 %t365) + store ptr %t367, ptr %t355 + store i32 %t361, ptr %t354 + br label %put93 +put93: + %t368 = load ptr, ptr %t290 + %t369 = load ptr, ptr %t355 + %t370 = getelementptr inbounds ptr, ptr %t369, i32 %t356 + store ptr %t368, ptr %t370 + %t371 = add i32 %t356, 1 + store i32 %t371, ptr %t353 + br label %wcond73 +wend75: + call void @fn_eat_op(ptr @.str77) + %t372 = load ptr, ptr %t282 + store ptr %t372, ptr %retval + br label %ret +ifend72: + br label %ifend2 +ifend2: + %t373 = call ptr @fn_expr() + store ptr %t373, ptr %t374 + %t379 = call i32 @fn_is_op(ptr @.str78) + %t380 = icmp ne i32 %t379, 0 + %t381 = zext i1 %t380 to i32 + store i32 %t381, ptr %t378 + br i1 %t380, label %scend95, label %sc94 +sc94: + %t382 = call i32 @fn_is_op(ptr @.str79) + %t383 = icmp ne i32 %t382, 0 + %t384 = zext i1 %t383 to i32 + store i32 %t384, ptr %t378 + br label %scend95 +scend95: + %t385 = load i32, ptr %t378 + %t386 = icmp ne i32 %t385, 0 + %t387 = zext i1 %t386 to i32 + store i32 %t387, ptr %t377 + br i1 %t386, label %scend97, label %sc96 +sc96: + %t388 = call i32 @fn_is_op(ptr @.str80) + %t389 = icmp ne i32 %t388, 0 + %t390 = zext i1 %t389 to i32 + store i32 %t390, ptr %t377 + br label %scend97 +scend97: + %t391 = load i32, ptr %t377 + %t392 = icmp ne i32 %t391, 0 + %t393 = zext i1 %t392 to i32 + store i32 %t393, ptr %t376 + br i1 %t392, label %scend99, label %sc98 +sc98: + %t394 = call i32 @fn_is_op(ptr @.str81) + %t395 = icmp ne i32 %t394, 0 + %t396 = zext i1 %t395 to i32 + store i32 %t396, ptr %t376 + br label %scend99 +scend99: + %t397 = load i32, ptr %t376 + %t398 = icmp ne i32 %t397, 0 + %t399 = zext i1 %t398 to i32 + store i32 %t399, ptr %t375 + br i1 %t398, label %scend101, label %sc100 +sc100: + %t400 = call i32 @fn_is_op(ptr @.str82) + %t401 = icmp ne i32 %t400, 0 + %t402 = zext i1 %t401 to i32 + store i32 %t402, ptr %t375 + br label %scend101 +scend101: + %t403 = load i32, ptr %t375 + %t404 = icmp ne i32 %t403, 0 + br i1 %t404, label %then102, label %ifend104 +then102: + %t405 = call ptr @fn_node(i32 11) + store ptr %t405, ptr %t406 + %t407 = load ptr, ptr %t406 + %t408 = getelementptr inbounds %Str_Node, ptr %t407, i32 0, i32 1 + %t409 = load ptr, ptr @g_toks + %t410 = getelementptr inbounds %LSlice, ptr %t409, i32 0, i32 0 + %t411 = load ptr, ptr %t410 + %t412 = load i32, ptr @g_pi + %t413 = getelementptr inbounds ptr, ptr %t411, i32 %t412 + %t414 = load ptr, ptr %t413 + %t415 = getelementptr inbounds %Str_Tok, ptr %t414, i32 0, i32 1 + %t416 = load ptr, ptr %t415 + store ptr %t416, ptr %t408 + %t417 = load i32, ptr @g_pi + %t418 = add i32 %t417, 1 + store i32 %t418, ptr @g_pi + %t419 = load ptr, ptr %t406 + %t420 = getelementptr inbounds %Str_Node, ptr %t419, i32 0, i32 4 + %t421 = load ptr, ptr %t374 + store ptr %t421, ptr %t420 + %t422 = load ptr, ptr %t406 + %t423 = getelementptr inbounds %Str_Node, ptr %t422, i32 0, i32 5 + %t424 = call ptr @fn_expr() + store ptr %t424, ptr %t423 + %t425 = load ptr, ptr %t406 + store ptr %t425, ptr %retval + br label %ret +ifend104: + %t426 = call ptr @fn_node(i32 16) + store ptr %t426, ptr %t427 + %t428 = load ptr, ptr %t427 + %t429 = getelementptr inbounds %Str_Node, ptr %t428, i32 0, i32 4 + %t430 = load ptr, ptr %t374 + store ptr %t430, ptr %t429 + %t431 = load ptr, ptr %t427 + store ptr %t431, ptr %retval + br label %ret +ret: + %t432 = load ptr, ptr %retval + ret ptr %t432 +} + +define ptr @fn_parse_struct() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t11 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 0) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str83) + br label %wcond0 +wcond0: + %t7 = icmp ne i32 1, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + call void @fn_skipnl() + %t8 = call i32 @fn_is_op(ptr @.str84) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then3, label %ifend5 +then3: + br label %wend2 +ifend5: + %t10 = call ptr @fn_node(i32 1) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = call ptr @fn_eat_id() + store ptr %t14, ptr %t13 + call void @fn_eat_op(ptr @.str85) + %t15 = load ptr, ptr %t11 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 3 + %t17 = call ptr @fn_ptype() + store ptr %t17, ptr %t16 + %t18 = call i32 @fn_is_op(ptr @.str86) + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then6, label %ifend8 +then6: + %t20 = load i32, ptr @g_pi + %t21 = add i32 %t20, 1 + store i32 %t21, ptr @g_pi + %t22 = load ptr, ptr %t11 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 4 + %t24 = call ptr @fn_expr() + store ptr %t24, ptr %t23 + br label %ifend8 +ifend8: + %t25 = load ptr, ptr %t3 + %t26 = getelementptr inbounds %Str_Node, ptr %t25, i32 0, i32 7 + %t27 = load ptr, ptr %t26 + %t28 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 1 + %t29 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 2 + %t30 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 0 + %t31 = load i32, ptr %t28 + %t32 = load i32, ptr %t29 + %t33 = icmp sge i32 %t31, %t32 + br i1 %t33, label %grow9, label %put10 +grow9: + %t34 = mul i32 %t32, 2 + %t35 = icmp eq i32 %t32, 0 + %t36 = select i1 %t35, i32 8, i32 %t34 + %t37 = getelementptr ptr, ptr null, i32 1 + %t38 = ptrtoint ptr %t37 to i64 + %t39 = zext i32 %t36 to i64 + %t40 = mul i64 %t39, %t38 + %t41 = load ptr, ptr %t30 + %t42 = call ptr @realloc(ptr %t41, i64 %t40) + store ptr %t42, ptr %t30 + store i32 %t36, ptr %t29 + br label %put10 +put10: + %t43 = load ptr, ptr %t11 + %t44 = load ptr, ptr %t30 + %t45 = getelementptr inbounds ptr, ptr %t44, i32 %t31 + store ptr %t43, ptr %t45 + %t46 = add i32 %t31, 1 + store i32 %t46, ptr %t28 + %t47 = call i32 @fn_is_op(ptr @.str87) + %t48 = icmp ne i32 %t47, 0 + br i1 %t48, label %then11, label %ifend13 +then11: + %t49 = load i32, ptr @g_pi + %t50 = add i32 %t49, 1 + store i32 %t50, ptr @g_pi + br label %ifend13 +ifend13: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str88) + %t51 = load ptr, ptr %t3 + store ptr %t51, ptr %retval + br label %ret +ret: + %t52 = load ptr, ptr %retval + ret ptr %t52 +} + +define ptr @fn_parse_var() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 2) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_eat_op(ptr @.str89) + %t7 = load ptr, ptr %t3 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 3 + %t9 = call ptr @fn_ptype() + store ptr %t9, ptr %t8 + %t10 = call i32 @fn_is_op(ptr @.str90) + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %then0, label %ifend2 +then0: + %t12 = load i32, ptr @g_pi + %t13 = add i32 %t12, 1 + store i32 %t13, ptr @g_pi + %t14 = load ptr, ptr %t3 + %t15 = getelementptr inbounds %Str_Node, ptr %t14, i32 0, i32 4 + %t16 = call ptr @fn_expr() + store ptr %t16, ptr %t15 + br label %ifend2 +ifend2: + %t17 = load ptr, ptr %t3 + store ptr %t17, ptr %retval + br label %ret +ret: + %t18 = load ptr, ptr %retval + ret ptr %t18 +} + +define ptr @fn_parse_const() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 3) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_eat_op(ptr @.str91) + %t7 = load ptr, ptr %t3 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 3 + %t9 = call ptr @fn_ptype() + store ptr %t9, ptr %t8 + call void @fn_eat_op(ptr @.str92) + %t10 = load ptr, ptr %t3 + %t11 = getelementptr inbounds %Str_Node, ptr %t10, i32 0, i32 4 + %t12 = call ptr @fn_expr() + store ptr %t12, ptr %t11 + %t13 = load ptr, ptr %t3 + store ptr %t13, ptr %retval + br label %ret +ret: + %t14 = load ptr, ptr %retval + ret ptr %t14 +} + +define ptr @fn_parse_fn() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t12 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 4) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_eat_op(ptr @.str93) + br label %wcond0 +wcond0: + %t7 = call i32 @fn_is_op(ptr @.str94) + %t8 = icmp eq i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t11 = call ptr @fn_node(i32 5) + store ptr %t11, ptr %t12 + %t13 = load ptr, ptr %t12 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 1 + %t15 = call ptr @fn_eat_id() + store ptr %t15, ptr %t14 + call void @fn_eat_op(ptr @.str95) + %t16 = load ptr, ptr %t12 + %t17 = getelementptr inbounds %Str_Node, ptr %t16, i32 0, i32 3 + %t18 = call ptr @fn_ptype() + store ptr %t18, ptr %t17 + %t19 = load ptr, ptr %t3 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 7 + %t21 = load ptr, ptr %t20 + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 1 + %t23 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 2 + %t24 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 0 + %t25 = load i32, ptr %t22 + %t26 = load i32, ptr %t23 + %t27 = icmp sge i32 %t25, %t26 + br i1 %t27, label %grow3, label %put4 +grow3: + %t28 = mul i32 %t26, 2 + %t29 = icmp eq i32 %t26, 0 + %t30 = select i1 %t29, i32 8, i32 %t28 + %t31 = getelementptr ptr, ptr null, i32 1 + %t32 = ptrtoint ptr %t31 to i64 + %t33 = zext i32 %t30 to i64 + %t34 = mul i64 %t33, %t32 + %t35 = load ptr, ptr %t24 + %t36 = call ptr @realloc(ptr %t35, i64 %t34) + store ptr %t36, ptr %t24 + store i32 %t30, ptr %t23 + br label %put4 +put4: + %t37 = load ptr, ptr %t12 + %t38 = load ptr, ptr %t24 + %t39 = getelementptr inbounds ptr, ptr %t38, i32 %t25 + store ptr %t37, ptr %t39 + %t40 = add i32 %t25, 1 + store i32 %t40, ptr %t22 + %t41 = call i32 @fn_is_op(ptr @.str96) + %t42 = icmp ne i32 %t41, 0 + br i1 %t42, label %then5, label %ifend7 +then5: + %t43 = load i32, ptr @g_pi + %t44 = add i32 %t43, 1 + store i32 %t44, ptr @g_pi + br label %ifend7 +ifend7: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str97) + %t45 = load ptr, ptr %t3 + %t46 = getelementptr inbounds %Str_Node, ptr %t45, i32 0, i32 3 + store ptr @.str98, ptr %t46 + %t47 = call i32 @fn_is_op(ptr @.str99) + %t48 = icmp ne i32 %t47, 0 + br i1 %t48, label %then8, label %ifend10 +then8: + %t49 = load i32, ptr @g_pi + %t50 = add i32 %t49, 1 + store i32 %t50, ptr @g_pi + %t51 = load ptr, ptr %t3 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 3 + %t53 = call ptr @fn_ptype() + store ptr %t53, ptr %t52 + br label %ifend10 +ifend10: + %t54 = load ptr, ptr %t3 + %t55 = getelementptr inbounds %Str_Node, ptr %t54, i32 0, i32 4 + %t56 = call ptr @fn_block() + store ptr %t56, ptr %t55 + %t57 = load ptr, ptr %t3 + store ptr %t57, ptr %retval + br label %ret +ret: + %t58 = load ptr, ptr %retval + ret ptr %t58 +} + +define ptr @fn_parse_main() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 6) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 4 + %t6 = call ptr @fn_block() + store ptr %t6, ptr %t5 + %t7 = load ptr, ptr %t3 + store ptr %t7, ptr %retval + br label %ret +ret: + %t8 = load ptr, ptr %retval + ret ptr %t8 +} + +define ptr @fn_dir_of(ptr %arg_path) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t2 = alloca i32 + %t3 = alloca i32 + store ptr %arg_path, ptr %t0 + %t1 = sub i32 0, 1 + store i32 %t1, ptr %t2 + store i32 0, ptr %t3 + br label %wcond0 +wcond0: + %t4 = load ptr, ptr %t0 + %t5 = load i32, ptr %t3 + %t6 = getelementptr inbounds i8, ptr %t4, i32 %t5 + %t7 = load i8, ptr %t6 + %t8 = zext i8 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %wbody1, label %wend2 +wbody1: + %t12 = load ptr, ptr %t0 + %t13 = load i32, ptr %t3 + %t14 = getelementptr inbounds i8, ptr %t12, i32 %t13 + %t15 = load i8, ptr %t14 + %t16 = zext i8 %t15 to i32 + %t17 = icmp eq i32 %t16, 47 + %t18 = zext i1 %t17 to i32 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then3, label %ifend5 +then3: + %t20 = load i32, ptr %t3 + store i32 %t20, ptr %t2 + br label %ifend5 +ifend5: + %t21 = load i32, ptr %t3 + %t22 = add i32 %t21, 1 + store i32 %t22, ptr %t3 + br label %wcond0 +wend2: + %t23 = load i32, ptr %t2 + %t24 = icmp slt i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %then6, label %ifend8 +then6: + store ptr @.str100, ptr %retval + br label %ret +ifend8: + %t27 = load ptr, ptr %t0 + %t28 = load i32, ptr %t2 + %t29 = add i32 %t28, 1 + %t30 = call ptr @fn_substr(ptr %t27, i32 0, i32 %t29) + store ptr %t30, ptr %retval + br label %ret +ret: + %t31 = load ptr, ptr %retval + ret ptr %t31 +} + +define ptr @fn_path_join(ptr %arg_dir, ptr %arg_rel) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + store ptr %arg_dir, ptr %t0 + store ptr %arg_rel, ptr %t1 + %t2 = load ptr, ptr %t1 + %t3 = getelementptr inbounds i8, ptr %t2, i32 0 + %t4 = load i8, ptr %t3 + %t5 = zext i8 %t4 to i32 + %t6 = icmp eq i32 %t5, 47 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %then0, label %ifend2 +then0: + %t9 = load ptr, ptr %t1 + store ptr %t9, ptr %retval + br label %ret +ifend2: + %t10 = load ptr, ptr %t0 + %t11 = load ptr, ptr %t1 + %t12 = call ptr @fn_sconcat(ptr %t10, ptr %t11) + store ptr %t12, ptr %retval + br label %ret +ret: + %t13 = load ptr, ptr %retval + ret ptr %t13 +} + +define i32 @fn_already_loaded(ptr %arg_full) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_full, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_loaded_paths + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_loaded_paths + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + %t15 = load ptr, ptr %t0 + %t16 = call i32 @fn_streq(ptr %t14, ptr %t15) + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %then3, label %ifend5 +then3: + store i32 1, ptr %retval + br label %ret +ifend5: + %t18 = load i32, ptr %t1 + %t19 = add i32 %t18, 1 + store i32 %t19, ptr %t1 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t20 = load i32, ptr %retval + ret i32 %t20 +} + +define void @fn_parse_one_decl() { +entry: + %t10 = alloca ptr + %t20 = alloca ptr + %t90 = alloca i32 + %t190 = alloca ptr + %t213 = alloca i32 + %t0 = call i32 @fn_is_id(ptr @.str101) + %t1 = icmp ne i32 %t0, 0 + br i1 %t1, label %then0, label %ifend2 +then0: + %t2 = load i32, ptr @g_pi + %t3 = add i32 %t2, 1 + store i32 %t3, ptr @g_pi + %t4 = load ptr, ptr @g_toks + %t5 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 0 + %t6 = load ptr, ptr %t5 + %t7 = load i32, ptr @g_pi + %t8 = getelementptr inbounds ptr, ptr %t6, i32 %t7 + %t9 = load ptr, ptr %t8 + store ptr %t9, ptr %t10 + %t11 = load ptr, ptr %t10 + %t12 = getelementptr inbounds %Str_Tok, ptr %t11, i32 0, i32 0 + %t13 = load i32, ptr %t12 + %t14 = icmp ne i32 %t13, 2 + %t15 = zext i1 %t14 to i32 + %t16 = icmp ne i32 %t15, 0 + br i1 %t16, label %then3, label %ifend5 +then3: + call void @fn_perr(ptr @.str102) + br label %ifend5 +ifend5: + %t17 = load ptr, ptr %t10 + %t18 = getelementptr inbounds %Str_Tok, ptr %t17, i32 0, i32 1 + %t19 = load ptr, ptr %t18 + store ptr %t19, ptr %t20 + %t21 = load i32, ptr @g_pi + %t22 = add i32 %t21, 1 + store i32 %t22, ptr @g_pi + %t23 = load ptr, ptr %t20 + call void @fn_do_import(ptr %t23) + br label %ret +ifend2: + %t24 = call i32 @fn_is_id(ptr @.str103) + %t25 = icmp ne i32 %t24, 0 + br i1 %t25, label %then6, label %ifend8 +then6: + %t26 = load ptr, ptr @g_prog + %t27 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 1 + %t28 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 2 + %t29 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 0 + %t30 = load i32, ptr %t27 + %t31 = load i32, ptr %t28 + %t32 = icmp sge i32 %t30, %t31 + br i1 %t32, label %grow9, label %put10 +grow9: + %t33 = mul i32 %t31, 2 + %t34 = icmp eq i32 %t31, 0 + %t35 = select i1 %t34, i32 8, i32 %t33 + %t36 = getelementptr ptr, ptr null, i32 1 + %t37 = ptrtoint ptr %t36 to i64 + %t38 = zext i32 %t35 to i64 + %t39 = mul i64 %t38, %t37 + %t40 = load ptr, ptr %t29 + %t41 = call ptr @realloc(ptr %t40, i64 %t39) + store ptr %t41, ptr %t29 + store i32 %t35, ptr %t28 + br label %put10 +put10: + %t42 = call ptr @fn_parse_struct() + %t43 = load ptr, ptr %t29 + %t44 = getelementptr inbounds ptr, ptr %t43, i32 %t30 + store ptr %t42, ptr %t44 + %t45 = add i32 %t30, 1 + store i32 %t45, ptr %t27 + br label %ret +ifend8: + %t46 = call i32 @fn_is_id(ptr @.str104) + %t47 = icmp ne i32 %t46, 0 + br i1 %t47, label %then11, label %ifend13 +then11: + %t48 = load ptr, ptr @g_prog + %t49 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 1 + %t50 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 2 + %t51 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 0 + %t52 = load i32, ptr %t49 + %t53 = load i32, ptr %t50 + %t54 = icmp sge i32 %t52, %t53 + br i1 %t54, label %grow14, label %put15 +grow14: + %t55 = mul i32 %t53, 2 + %t56 = icmp eq i32 %t53, 0 + %t57 = select i1 %t56, i32 8, i32 %t55 + %t58 = getelementptr ptr, ptr null, i32 1 + %t59 = ptrtoint ptr %t58 to i64 + %t60 = zext i32 %t57 to i64 + %t61 = mul i64 %t60, %t59 + %t62 = load ptr, ptr %t51 + %t63 = call ptr @realloc(ptr %t62, i64 %t61) + store ptr %t63, ptr %t51 + store i32 %t57, ptr %t50 + br label %put15 +put15: + %t64 = call ptr @fn_parse_component() + %t65 = load ptr, ptr %t51 + %t66 = getelementptr inbounds ptr, ptr %t65, i32 %t52 + store ptr %t64, ptr %t66 + %t67 = add i32 %t52, 1 + store i32 %t67, ptr %t49 + br label %ret +ifend13: + %t68 = call i32 @fn_is_id(ptr @.str105) + %t69 = icmp ne i32 %t68, 0 + br i1 %t69, label %then16, label %ifend18 +then16: + %t70 = load ptr, ptr @g_prog + %t71 = getelementptr inbounds %LSlice, ptr %t70, i32 0, i32 1 + %t72 = getelementptr inbounds %LSlice, ptr %t70, i32 0, i32 2 + %t73 = getelementptr inbounds %LSlice, ptr %t70, i32 0, i32 0 + %t74 = load i32, ptr %t71 + %t75 = load i32, ptr %t72 + %t76 = icmp sge i32 %t74, %t75 + br i1 %t76, label %grow19, label %put20 +grow19: + %t77 = mul i32 %t75, 2 + %t78 = icmp eq i32 %t75, 0 + %t79 = select i1 %t78, i32 8, i32 %t77 + %t80 = getelementptr ptr, ptr null, i32 1 + %t81 = ptrtoint ptr %t80 to i64 + %t82 = zext i32 %t79 to i64 + %t83 = mul i64 %t82, %t81 + %t84 = load ptr, ptr %t73 + %t85 = call ptr @realloc(ptr %t84, i64 %t83) + store ptr %t85, ptr %t73 + store i32 %t79, ptr %t72 + br label %put20 +put20: + %t86 = call ptr @fn_parse_archetype() + %t87 = load ptr, ptr %t73 + %t88 = getelementptr inbounds ptr, ptr %t87, i32 %t74 + store ptr %t86, ptr %t88 + %t89 = add i32 %t74, 1 + store i32 %t89, ptr %t71 + br label %ret +ifend18: + %t91 = call i32 @fn_is_id(ptr @.str106) + %t92 = icmp ne i32 %t91, 0 + %t93 = zext i1 %t92 to i32 + store i32 %t93, ptr %t90 + br i1 %t92, label %scend22, label %sc21 +sc21: + %t94 = call i32 @fn_is_id(ptr @.str107) + %t95 = icmp ne i32 %t94, 0 + %t96 = zext i1 %t95 to i32 + store i32 %t96, ptr %t90 + br label %scend22 +scend22: + %t97 = load i32, ptr %t90 + %t98 = icmp ne i32 %t97, 0 + br i1 %t98, label %then23, label %ifend25 +then23: + %t99 = load ptr, ptr @g_prog + %t100 = getelementptr inbounds %LSlice, ptr %t99, i32 0, i32 1 + %t101 = getelementptr inbounds %LSlice, ptr %t99, i32 0, i32 2 + %t102 = getelementptr inbounds %LSlice, ptr %t99, i32 0, i32 0 + %t103 = load i32, ptr %t100 + %t104 = load i32, ptr %t101 + %t105 = icmp sge i32 %t103, %t104 + br i1 %t105, label %grow26, label %put27 +grow26: + %t106 = mul i32 %t104, 2 + %t107 = icmp eq i32 %t104, 0 + %t108 = select i1 %t107, i32 8, i32 %t106 + %t109 = getelementptr ptr, ptr null, i32 1 + %t110 = ptrtoint ptr %t109 to i64 + %t111 = zext i32 %t108 to i64 + %t112 = mul i64 %t111, %t110 + %t113 = load ptr, ptr %t102 + %t114 = call ptr @realloc(ptr %t113, i64 %t112) + store ptr %t114, ptr %t102 + store i32 %t108, ptr %t101 + br label %put27 +put27: + %t115 = call ptr @fn_parse_system() + %t116 = load ptr, ptr %t102 + %t117 = getelementptr inbounds ptr, ptr %t116, i32 %t103 + store ptr %t115, ptr %t117 + %t118 = add i32 %t103, 1 + store i32 %t118, ptr %t100 + br label %ret +ifend25: + %t119 = call i32 @fn_is_id(ptr @.str108) + %t120 = icmp ne i32 %t119, 0 + br i1 %t120, label %then28, label %ifend30 +then28: + %t121 = load ptr, ptr @g_prog + %t122 = getelementptr inbounds %LSlice, ptr %t121, i32 0, i32 1 + %t123 = getelementptr inbounds %LSlice, ptr %t121, i32 0, i32 2 + %t124 = getelementptr inbounds %LSlice, ptr %t121, i32 0, i32 0 + %t125 = load i32, ptr %t122 + %t126 = load i32, ptr %t123 + %t127 = icmp sge i32 %t125, %t126 + br i1 %t127, label %grow31, label %put32 +grow31: + %t128 = mul i32 %t126, 2 + %t129 = icmp eq i32 %t126, 0 + %t130 = select i1 %t129, i32 8, i32 %t128 + %t131 = getelementptr ptr, ptr null, i32 1 + %t132 = ptrtoint ptr %t131 to i64 + %t133 = zext i32 %t130 to i64 + %t134 = mul i64 %t133, %t132 + %t135 = load ptr, ptr %t124 + %t136 = call ptr @realloc(ptr %t135, i64 %t134) + store ptr %t136, ptr %t124 + store i32 %t130, ptr %t123 + br label %put32 +put32: + %t137 = call ptr @fn_parse_ui() + %t138 = load ptr, ptr %t124 + %t139 = getelementptr inbounds ptr, ptr %t138, i32 %t125 + store ptr %t137, ptr %t139 + %t140 = add i32 %t125, 1 + store i32 %t140, ptr %t122 + br label %ret +ifend30: + %t141 = call i32 @fn_is_id(ptr @.str109) + %t142 = icmp ne i32 %t141, 0 + br i1 %t142, label %then33, label %ifend35 +then33: + %t143 = load ptr, ptr @g_prog + %t144 = getelementptr inbounds %LSlice, ptr %t143, i32 0, i32 1 + %t145 = getelementptr inbounds %LSlice, ptr %t143, i32 0, i32 2 + %t146 = getelementptr inbounds %LSlice, ptr %t143, i32 0, i32 0 + %t147 = load i32, ptr %t144 + %t148 = load i32, ptr %t145 + %t149 = icmp sge i32 %t147, %t148 + br i1 %t149, label %grow36, label %put37 +grow36: + %t150 = mul i32 %t148, 2 + %t151 = icmp eq i32 %t148, 0 + %t152 = select i1 %t151, i32 8, i32 %t150 + %t153 = getelementptr ptr, ptr null, i32 1 + %t154 = ptrtoint ptr %t153 to i64 + %t155 = zext i32 %t152 to i64 + %t156 = mul i64 %t155, %t154 + %t157 = load ptr, ptr %t146 + %t158 = call ptr @realloc(ptr %t157, i64 %t156) + store ptr %t158, ptr %t146 + store i32 %t152, ptr %t145 + br label %put37 +put37: + %t159 = call ptr @fn_parse_var() + %t160 = load ptr, ptr %t146 + %t161 = getelementptr inbounds ptr, ptr %t160, i32 %t147 + store ptr %t159, ptr %t161 + %t162 = add i32 %t147, 1 + store i32 %t162, ptr %t144 + br label %ret +ifend35: + %t163 = call i32 @fn_is_id(ptr @.str110) + %t164 = icmp ne i32 %t163, 0 + br i1 %t164, label %then38, label %ifend40 +then38: + %t165 = load ptr, ptr @g_prog + %t166 = getelementptr inbounds %LSlice, ptr %t165, i32 0, i32 1 + %t167 = getelementptr inbounds %LSlice, ptr %t165, i32 0, i32 2 + %t168 = getelementptr inbounds %LSlice, ptr %t165, i32 0, i32 0 + %t169 = load i32, ptr %t166 + %t170 = load i32, ptr %t167 + %t171 = icmp sge i32 %t169, %t170 + br i1 %t171, label %grow41, label %put42 +grow41: + %t172 = mul i32 %t170, 2 + %t173 = icmp eq i32 %t170, 0 + %t174 = select i1 %t173, i32 8, i32 %t172 + %t175 = getelementptr ptr, ptr null, i32 1 + %t176 = ptrtoint ptr %t175 to i64 + %t177 = zext i32 %t174 to i64 + %t178 = mul i64 %t177, %t176 + %t179 = load ptr, ptr %t168 + %t180 = call ptr @realloc(ptr %t179, i64 %t178) + store ptr %t180, ptr %t168 + store i32 %t174, ptr %t167 + br label %put42 +put42: + %t181 = call ptr @fn_parse_const() + %t182 = load ptr, ptr %t168 + %t183 = getelementptr inbounds ptr, ptr %t182, i32 %t169 + store ptr %t181, ptr %t183 + %t184 = add i32 %t169, 1 + store i32 %t184, ptr %t166 + br label %ret +ifend40: + %t185 = call i32 @fn_is_id(ptr @.str111) + %t186 = icmp ne i32 %t185, 0 + br i1 %t186, label %then43, label %ifend45 +then43: + %t187 = load i32, ptr @g_pi + %t188 = add i32 %t187, 1 + store i32 %t188, ptr @g_pi + %t189 = call ptr @fn_parse_fn() + store ptr %t189, ptr %t190 + %t191 = load ptr, ptr %t190 + %t192 = getelementptr inbounds %Str_Node, ptr %t191, i32 0, i32 2 + store i32 1, ptr %t192 + %t193 = load ptr, ptr @g_prog + %t194 = getelementptr inbounds %LSlice, ptr %t193, i32 0, i32 1 + %t195 = getelementptr inbounds %LSlice, ptr %t193, i32 0, i32 2 + %t196 = getelementptr inbounds %LSlice, ptr %t193, i32 0, i32 0 + %t197 = load i32, ptr %t194 + %t198 = load i32, ptr %t195 + %t199 = icmp sge i32 %t197, %t198 + br i1 %t199, label %grow46, label %put47 +grow46: + %t200 = mul i32 %t198, 2 + %t201 = icmp eq i32 %t198, 0 + %t202 = select i1 %t201, i32 8, i32 %t200 + %t203 = getelementptr ptr, ptr null, i32 1 + %t204 = ptrtoint ptr %t203 to i64 + %t205 = zext i32 %t202 to i64 + %t206 = mul i64 %t205, %t204 + %t207 = load ptr, ptr %t196 + %t208 = call ptr @realloc(ptr %t207, i64 %t206) + store ptr %t208, ptr %t196 + store i32 %t202, ptr %t195 + br label %put47 +put47: + %t209 = load ptr, ptr %t190 + %t210 = load ptr, ptr %t196 + %t211 = getelementptr inbounds ptr, ptr %t210, i32 %t197 + store ptr %t209, ptr %t211 + %t212 = add i32 %t197, 1 + store i32 %t212, ptr %t194 + br label %ret +ifend45: + %t214 = call i32 @fn_is_id(ptr @.str112) + %t215 = icmp ne i32 %t214, 0 + %t216 = zext i1 %t215 to i32 + store i32 %t216, ptr %t213 + br i1 %t215, label %scend49, label %sc48 +sc48: + %t217 = call i32 @fn_is_id(ptr @.str113) + %t218 = icmp ne i32 %t217, 0 + %t219 = zext i1 %t218 to i32 + store i32 %t219, ptr %t213 + br label %scend49 +scend49: + %t220 = load i32, ptr %t213 + %t221 = icmp ne i32 %t220, 0 + br i1 %t221, label %then50, label %ifend52 +then50: + %t222 = call i32 @fn_is_id(ptr @.str114) + %t223 = icmp ne i32 %t222, 0 + br i1 %t223, label %then53, label %ifend55 +then53: + %t224 = load i32, ptr @g_pi + %t225 = add i32 %t224, 1 + store i32 %t225, ptr @g_pi + br label %ifend55 +ifend55: + %t226 = load ptr, ptr @g_prog + %t227 = getelementptr inbounds %LSlice, ptr %t226, i32 0, i32 1 + %t228 = getelementptr inbounds %LSlice, ptr %t226, i32 0, i32 2 + %t229 = getelementptr inbounds %LSlice, ptr %t226, i32 0, i32 0 + %t230 = load i32, ptr %t227 + %t231 = load i32, ptr %t228 + %t232 = icmp sge i32 %t230, %t231 + br i1 %t232, label %grow56, label %put57 +grow56: + %t233 = mul i32 %t231, 2 + %t234 = icmp eq i32 %t231, 0 + %t235 = select i1 %t234, i32 8, i32 %t233 + %t236 = getelementptr ptr, ptr null, i32 1 + %t237 = ptrtoint ptr %t236 to i64 + %t238 = zext i32 %t235 to i64 + %t239 = mul i64 %t238, %t237 + %t240 = load ptr, ptr %t229 + %t241 = call ptr @realloc(ptr %t240, i64 %t239) + store ptr %t241, ptr %t229 + store i32 %t235, ptr %t228 + br label %put57 +put57: + %t242 = call ptr @fn_parse_fn() + %t243 = load ptr, ptr %t229 + %t244 = getelementptr inbounds ptr, ptr %t243, i32 %t230 + store ptr %t242, ptr %t244 + %t245 = add i32 %t230, 1 + store i32 %t245, ptr %t227 + br label %ret +ifend52: + %t246 = call i32 @fn_is_id(ptr @.str115) + %t247 = icmp ne i32 %t246, 0 + br i1 %t247, label %then58, label %ifend60 +then58: + %t248 = load ptr, ptr @g_prog + %t249 = getelementptr inbounds %LSlice, ptr %t248, i32 0, i32 1 + %t250 = getelementptr inbounds %LSlice, ptr %t248, i32 0, i32 2 + %t251 = getelementptr inbounds %LSlice, ptr %t248, i32 0, i32 0 + %t252 = load i32, ptr %t249 + %t253 = load i32, ptr %t250 + %t254 = icmp sge i32 %t252, %t253 + br i1 %t254, label %grow61, label %put62 +grow61: + %t255 = mul i32 %t253, 2 + %t256 = icmp eq i32 %t253, 0 + %t257 = select i1 %t256, i32 8, i32 %t255 + %t258 = getelementptr ptr, ptr null, i32 1 + %t259 = ptrtoint ptr %t258 to i64 + %t260 = zext i32 %t257 to i64 + %t261 = mul i64 %t260, %t259 + %t262 = load ptr, ptr %t251 + %t263 = call ptr @realloc(ptr %t262, i64 %t261) + store ptr %t263, ptr %t251 + store i32 %t257, ptr %t250 + br label %put62 +put62: + %t264 = call ptr @fn_parse_extern() + %t265 = load ptr, ptr %t251 + %t266 = getelementptr inbounds ptr, ptr %t265, i32 %t252 + store ptr %t264, ptr %t266 + %t267 = add i32 %t252, 1 + store i32 %t267, ptr %t249 + br label %ret +ifend60: + %t268 = call i32 @fn_is_id(ptr @.str116) + %t269 = icmp ne i32 %t268, 0 + br i1 %t269, label %then63, label %ifend65 +then63: + %t270 = load ptr, ptr @g_prog + %t271 = getelementptr inbounds %LSlice, ptr %t270, i32 0, i32 1 + %t272 = getelementptr inbounds %LSlice, ptr %t270, i32 0, i32 2 + %t273 = getelementptr inbounds %LSlice, ptr %t270, i32 0, i32 0 + %t274 = load i32, ptr %t271 + %t275 = load i32, ptr %t272 + %t276 = icmp sge i32 %t274, %t275 + br i1 %t276, label %grow66, label %put67 +grow66: + %t277 = mul i32 %t275, 2 + %t278 = icmp eq i32 %t275, 0 + %t279 = select i1 %t278, i32 8, i32 %t277 + %t280 = getelementptr ptr, ptr null, i32 1 + %t281 = ptrtoint ptr %t280 to i64 + %t282 = zext i32 %t279 to i64 + %t283 = mul i64 %t282, %t281 + %t284 = load ptr, ptr %t273 + %t285 = call ptr @realloc(ptr %t284, i64 %t283) + store ptr %t285, ptr %t273 + store i32 %t279, ptr %t272 + br label %put67 +put67: + %t286 = call ptr @fn_parse_main() + %t287 = load ptr, ptr %t273 + %t288 = getelementptr inbounds ptr, ptr %t287, i32 %t274 + store ptr %t286, ptr %t288 + %t289 = add i32 %t274, 1 + store i32 %t289, ptr %t271 + br label %ret +ifend65: + call void @fn_perr(ptr @.str117) + br label %ret +ret: + ret void +} + +define void @fn_do_import(ptr %arg_rel) { +entry: + %t0 = alloca ptr + %t4 = alloca ptr + %t30 = alloca ptr + %t38 = alloca ptr + %t40 = alloca i32 + %t42 = alloca ptr + store ptr %arg_rel, ptr %t0 + %t1 = load ptr, ptr @g_cur_dir + %t2 = load ptr, ptr %t0 + %t3 = call ptr @fn_path_join(ptr %t1, ptr %t2) + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t4 + %t6 = call i32 @fn_already_loaded(ptr %t5) + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + br label %ret +ifend2: + %t8 = load ptr, ptr @g_loaded_paths + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 1 + %t10 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 2 + %t11 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + %t12 = load i32, ptr %t9 + %t13 = load i32, ptr %t10 + %t14 = icmp sge i32 %t12, %t13 + br i1 %t14, label %grow3, label %put4 +grow3: + %t15 = mul i32 %t13, 2 + %t16 = icmp eq i32 %t13, 0 + %t17 = select i1 %t16, i32 8, i32 %t15 + %t18 = getelementptr ptr, ptr null, i32 1 + %t19 = ptrtoint ptr %t18 to i64 + %t20 = zext i32 %t17 to i64 + %t21 = mul i64 %t20, %t19 + %t22 = load ptr, ptr %t11 + %t23 = call ptr @realloc(ptr %t22, i64 %t21) + store ptr %t23, ptr %t11 + store i32 %t17, ptr %t10 + br label %put4 +put4: + %t24 = load ptr, ptr %t4 + %t25 = load ptr, ptr %t11 + %t26 = getelementptr inbounds ptr, ptr %t25, i32 %t12 + store ptr %t24, ptr %t26 + %t27 = add i32 %t12, 1 + store i32 %t27, ptr %t9 + %t28 = load ptr, ptr %t4 + %t29 = call ptr @fn_read_file(ptr %t28) + store ptr %t29, ptr %t30 + %t31 = load ptr, ptr %t30 + %t32 = icmp eq ptr %t31, null + %t33 = zext i1 %t32 to i32 + %t34 = icmp ne i32 %t33, 0 + br i1 %t34, label %then5, label %ifend7 +then5: + %t35 = load ptr, ptr %t4 + %t36 = call ptr @fn_sconcat(ptr @.str118, ptr %t35) + call void @fn_perr(ptr %t36) + br label %ifend7 +ifend7: + %t37 = load ptr, ptr @g_toks + store ptr %t37, ptr %t38 + %t39 = load i32, ptr @g_pi + store i32 %t39, ptr %t40 + %t41 = load ptr, ptr @g_cur_dir + store ptr %t41, ptr %t42 + %t43 = load ptr, ptr %t4 + %t44 = call ptr @fn_dir_of(ptr %t43) + store ptr %t44, ptr @g_cur_dir + %t45 = load ptr, ptr %t30 + call void @fn_lex(ptr %t45) + store i32 0, ptr @g_pi + call void @fn_skipnl() + br label %wcond8 +wcond8: + %t46 = load ptr, ptr @g_toks + %t47 = getelementptr inbounds %LSlice, ptr %t46, i32 0, i32 0 + %t48 = load ptr, ptr %t47 + %t49 = load i32, ptr @g_pi + %t50 = getelementptr inbounds ptr, ptr %t48, i32 %t49 + %t51 = load ptr, ptr %t50 + %t52 = getelementptr inbounds %Str_Tok, ptr %t51, i32 0, i32 0 + %t53 = load i32, ptr %t52 + %t54 = icmp ne i32 %t53, 5 + %t55 = zext i1 %t54 to i32 + %t56 = icmp ne i32 %t55, 0 + br i1 %t56, label %wbody9, label %wend10 +wbody9: + call void @fn_parse_one_decl() + call void @fn_skipnl() + br label %wcond8 +wend10: + %t57 = load ptr, ptr %t38 + store ptr %t57, ptr @g_toks + %t58 = load i32, ptr %t40 + store i32 %t58, ptr @g_pi + %t59 = load ptr, ptr %t42 + store ptr %t59, ptr @g_cur_dir + br label %ret +ret: + ret void +} + +define void @fn_maybe_splice_runtime() { +entry: + %t5 = alloca ptr + %t0 = call i32 @fn_has_ecs() + %t1 = icmp eq i32 %t0, 0 + %t2 = zext i1 %t1 to i32 + %t3 = icmp ne i32 %t2, 0 + br i1 %t3, label %then0, label %ifend2 +then0: + br label %ret +ifend2: + %t4 = load ptr, ptr @g_cur_dir + store ptr %t4, ptr %t5 + store ptr @.str119, ptr @g_cur_dir + call void @fn_do_import(ptr @.str120) + %t6 = load ptr, ptr %t5 + store ptr %t6, ptr @g_cur_dir + br label %ret +ret: + ret void +} + +define void @fn_parse_program() { +entry: + %t22 = alloca ptr + %t26 = alloca ptr + %t30 = alloca i32 + %t0 = getelementptr %LSlice, ptr null, i32 1 + %t1 = ptrtoint ptr %t0 to i64 + %t2 = call ptr @malloc(i64 %t1) + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 0 + store ptr null, ptr %t3 + %t4 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + store i32 0, ptr %t4 + %t5 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 2 + store i32 0, ptr %t5 + store ptr %t2, ptr @g_prog + %t6 = getelementptr %LSlice, ptr null, i32 1 + %t7 = ptrtoint ptr %t6 to i64 + %t8 = call ptr @malloc(i64 %t7) + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + store ptr null, ptr %t9 + %t10 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 1 + store i32 0, ptr %t10 + %t11 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 2 + store i32 0, ptr %t11 + store ptr %t8, ptr @g_loaded_paths + call void @fn_skipnl() + store ptr @.str121, ptr @g_g_game_name + br label %wcond0 +wcond0: + %t12 = call i32 @fn_is_id(ptr @.str122) + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %wbody1, label %wend2 +wbody1: + %t14 = load i32, ptr @g_pi + %t15 = add i32 %t14, 1 + store i32 %t15, ptr @g_pi + %t16 = load ptr, ptr @g_toks + %t17 = getelementptr inbounds %LSlice, ptr %t16, i32 0, i32 0 + %t18 = load ptr, ptr %t17 + %t19 = load i32, ptr @g_pi + %t20 = getelementptr inbounds ptr, ptr %t18, i32 %t19 + %t21 = load ptr, ptr %t20 + store ptr %t21, ptr %t22 + %t23 = load ptr, ptr %t22 + %t24 = getelementptr inbounds %Str_Tok, ptr %t23, i32 0, i32 1 + %t25 = load ptr, ptr %t24 + store ptr %t25, ptr %t26 + %t27 = load i32, ptr @g_pi + %t28 = add i32 %t27, 1 + store i32 %t28, ptr @g_pi + %t29 = load ptr, ptr %t26 + call void @fn_do_import(ptr %t29) + call void @fn_skipnl() + br label %wcond0 +wend2: + %t31 = call i32 @fn_is_id(ptr @.str123) + %t32 = icmp ne i32 %t31, 0 + %t33 = zext i1 %t32 to i32 + store i32 %t33, ptr %t30 + br i1 %t32, label %scend4, label %sc3 +sc3: + %t34 = call i32 @fn_is_id(ptr @.str124) + %t35 = icmp ne i32 %t34, 0 + %t36 = zext i1 %t35 to i32 + store i32 %t36, ptr %t30 + br label %scend4 +scend4: + %t37 = load i32, ptr %t30 + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %then5, label %ifend7 +then5: + %t39 = load i32, ptr @g_pi + %t40 = add i32 %t39, 1 + store i32 %t40, ptr @g_pi + %t41 = call ptr @fn_eat_id() + store ptr %t41, ptr @g_g_game_name + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str125) + br label %ifend7 +ifend7: + br label %wcond8 +wcond8: + %t42 = icmp ne i32 1, 0 + br i1 %t42, label %wbody9, label %wend10 +wbody9: + call void @fn_skipnl() + %t43 = load ptr, ptr @g_toks + %t44 = getelementptr inbounds %LSlice, ptr %t43, i32 0, i32 0 + %t45 = load ptr, ptr %t44 + %t46 = load i32, ptr @g_pi + %t47 = getelementptr inbounds ptr, ptr %t45, i32 %t46 + %t48 = load ptr, ptr %t47 + %t49 = getelementptr inbounds %Str_Tok, ptr %t48, i32 0, i32 0 + %t50 = load i32, ptr %t49 + %t51 = icmp eq i32 %t50, 5 + %t52 = zext i1 %t51 to i32 + %t53 = icmp ne i32 %t52, 0 + br i1 %t53, label %then11, label %ifend13 +then11: + br label %wend10 +ifend13: + %t54 = call i32 @fn_is_op(ptr @.str126) + %t55 = icmp ne i32 %t54, 0 + br i1 %t55, label %then14, label %ifend16 +then14: + br label %wend10 +ifend16: + call void @fn_parse_one_decl() + br label %wcond8 +wend10: + br label %ret +ret: + ret void +} + +define ptr @fn_parse_component() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t11 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 8) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str127) + br label %wcond0 +wcond0: + %t7 = icmp ne i32 1, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + call void @fn_skipnl() + %t8 = call i32 @fn_is_op(ptr @.str128) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then3, label %ifend5 +then3: + br label %wend2 +ifend5: + %t10 = call ptr @fn_node(i32 1) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = call ptr @fn_eat_id() + store ptr %t14, ptr %t13 + call void @fn_eat_op(ptr @.str129) + %t15 = load ptr, ptr %t11 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 3 + %t17 = call ptr @fn_ptype() + store ptr %t17, ptr %t16 + %t18 = call i32 @fn_is_op(ptr @.str130) + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then6, label %ifend8 +then6: + %t20 = load i32, ptr @g_pi + %t21 = add i32 %t20, 1 + store i32 %t21, ptr @g_pi + %t22 = load ptr, ptr %t11 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 4 + %t24 = call ptr @fn_expr() + store ptr %t24, ptr %t23 + br label %ifend8 +ifend8: + %t25 = load ptr, ptr %t3 + %t26 = getelementptr inbounds %Str_Node, ptr %t25, i32 0, i32 7 + %t27 = load ptr, ptr %t26 + %t28 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 1 + %t29 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 2 + %t30 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 0 + %t31 = load i32, ptr %t28 + %t32 = load i32, ptr %t29 + %t33 = icmp sge i32 %t31, %t32 + br i1 %t33, label %grow9, label %put10 +grow9: + %t34 = mul i32 %t32, 2 + %t35 = icmp eq i32 %t32, 0 + %t36 = select i1 %t35, i32 8, i32 %t34 + %t37 = getelementptr ptr, ptr null, i32 1 + %t38 = ptrtoint ptr %t37 to i64 + %t39 = zext i32 %t36 to i64 + %t40 = mul i64 %t39, %t38 + %t41 = load ptr, ptr %t30 + %t42 = call ptr @realloc(ptr %t41, i64 %t40) + store ptr %t42, ptr %t30 + store i32 %t36, ptr %t29 + br label %put10 +put10: + %t43 = load ptr, ptr %t11 + %t44 = load ptr, ptr %t30 + %t45 = getelementptr inbounds ptr, ptr %t44, i32 %t31 + store ptr %t43, ptr %t45 + %t46 = add i32 %t31, 1 + store i32 %t46, ptr %t28 + %t47 = call i32 @fn_is_op(ptr @.str131) + %t48 = icmp ne i32 %t47, 0 + br i1 %t48, label %then11, label %ifend13 +then11: + %t49 = load i32, ptr @g_pi + %t50 = add i32 %t49, 1 + store i32 %t50, ptr @g_pi + br label %ifend13 +ifend13: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str132) + %t51 = load ptr, ptr %t3 + store ptr %t51, ptr %retval + br label %ret +ret: + %t52 = load ptr, ptr %retval + ret ptr %t52 +} + +define void @fn_skip_clause() { +entry: + %t2 = alloca i32 + %t0 = call i32 @fn_is_op(ptr @.str133) + %t1 = icmp ne i32 %t0, 0 + br i1 %t1, label %then0, label %ifend2 +then0: + store i32 0, ptr %t2 + br label %wcond3 +wcond3: + %t3 = icmp ne i32 1, 0 + br i1 %t3, label %wbody4, label %wend5 +wbody4: + %t4 = call i32 @fn_is_op(ptr @.str134) + %t5 = icmp ne i32 %t4, 0 + br i1 %t5, label %then6, label %ifend8 +then6: + %t6 = load i32, ptr %t2 + %t7 = add i32 %t6, 1 + store i32 %t7, ptr %t2 + br label %ifend8 +ifend8: + %t8 = call i32 @fn_is_op(ptr @.str135) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then9, label %ifend11 +then9: + %t10 = load i32, ptr %t2 + %t11 = sub i32 %t10, 1 + store i32 %t11, ptr %t2 + br label %ifend11 +ifend11: + %t12 = load i32, ptr @g_pi + %t13 = add i32 %t12, 1 + store i32 %t13, ptr @g_pi + %t14 = load i32, ptr %t2 + %t15 = icmp eq i32 %t14, 0 + %t16 = zext i1 %t15 to i32 + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %then12, label %ifend14 +then12: + br label %wend5 +ifend14: + br label %wcond3 +wend5: + br label %ifend2 +ifend2: + br label %ret +ret: + ret void +} + +define ptr @fn_parse_system() { +entry: + %retval = alloca ptr + %t7 = alloca ptr + %t13 = alloca i32 + %t15 = alloca ptr + %t22 = alloca ptr + %t25 = alloca i32 + %t48 = alloca i32 + %t49 = alloca i32 + %t50 = alloca i32 + %t84 = alloca ptr + %t125 = alloca ptr + %t132 = alloca ptr + %t0 = call i32 @fn_is_id(ptr @.str136) + %t1 = icmp ne i32 %t0, 0 + br i1 %t1, label %then0, label %ifend2 +then0: + %t2 = load i32, ptr @g_pi + %t3 = add i32 %t2, 1 + store i32 %t3, ptr @g_pi + br label %ifend2 +ifend2: + %t4 = load i32, ptr @g_pi + %t5 = add i32 %t4, 1 + store i32 %t5, ptr @g_pi + %t6 = call ptr @fn_node(i32 9) + store ptr %t6, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds %Str_Node, ptr %t8, i32 0, i32 1 + %t10 = call ptr @fn_eat_id() + store ptr %t10, ptr %t9 + %t11 = load ptr, ptr %t7 + %t12 = getelementptr inbounds %Str_Node, ptr %t11, i32 0, i32 3 + store ptr @.str137, ptr %t12 + store i32 0, ptr %t13 + %t14 = call ptr @fn_node(i32 21) + store ptr %t14, ptr %t15 + br label %wcond3 +wcond3: + %t16 = icmp ne i32 1, 0 + br i1 %t16, label %wbody4, label %wend5 +wbody4: + call void @fn_skipnl() + %t17 = call i32 @fn_is_op(ptr @.str138) + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %then6, label %ifend8 +then6: + %t19 = load i32, ptr @g_pi + %t20 = add i32 %t19, 1 + store i32 %t20, ptr @g_pi + %t21 = call ptr @fn_eat_id() + store ptr %t21, ptr %t22 + %t23 = call i32 @fn_is_op(ptr @.str139) + %t24 = icmp ne i32 %t23, 0 + br i1 %t24, label %then9, label %ifend11 +then9: + store i32 0, ptr %t25 + br label %wcond12 +wcond12: + %t26 = icmp ne i32 1, 0 + br i1 %t26, label %wbody13, label %wend14 +wbody13: + %t27 = call i32 @fn_is_op(ptr @.str140) + %t28 = icmp ne i32 %t27, 0 + br i1 %t28, label %then15, label %ifend17 +then15: + %t29 = load i32, ptr %t25 + %t30 = add i32 %t29, 1 + store i32 %t30, ptr %t25 + br label %ifend17 +ifend17: + %t31 = call i32 @fn_is_op(ptr @.str141) + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then18, label %ifend20 +then18: + %t33 = load i32, ptr %t25 + %t34 = sub i32 %t33, 1 + store i32 %t34, ptr %t25 + br label %ifend20 +ifend20: + %t35 = load i32, ptr @g_pi + %t36 = add i32 %t35, 1 + store i32 %t36, ptr @g_pi + %t37 = load i32, ptr %t25 + %t38 = icmp eq i32 %t37, 0 + %t39 = zext i1 %t38 to i32 + %t40 = icmp ne i32 %t39, 0 + br i1 %t40, label %then21, label %ifend23 +then21: + br label %wend14 +ifend23: + br label %wcond12 +wend14: + br label %ifend11 +ifend11: + br label %wcond3 +ifend8: + %t41 = call i32 @fn_is_id(ptr @.str142) + %t42 = icmp ne i32 %t41, 0 + br i1 %t42, label %then24, label %ifend26 +then24: + %t43 = load i32, ptr @g_pi + %t44 = add i32 %t43, 1 + store i32 %t44, ptr @g_pi + %t45 = load ptr, ptr %t7 + %t46 = getelementptr inbounds %Str_Node, ptr %t45, i32 0, i32 3 + %t47 = call ptr @fn_eat_id() + store ptr %t47, ptr %t46 + br label %wcond3 +ifend26: + %t51 = call i32 @fn_is_id(ptr @.str143) + %t52 = icmp ne i32 %t51, 0 + %t53 = zext i1 %t52 to i32 + store i32 %t53, ptr %t50 + br i1 %t52, label %scend28, label %sc27 +sc27: + %t54 = call i32 @fn_is_id(ptr @.str144) + %t55 = icmp ne i32 %t54, 0 + %t56 = zext i1 %t55 to i32 + store i32 %t56, ptr %t50 + br label %scend28 +scend28: + %t57 = load i32, ptr %t50 + %t58 = icmp ne i32 %t57, 0 + %t59 = zext i1 %t58 to i32 + store i32 %t59, ptr %t49 + br i1 %t58, label %scend30, label %sc29 +sc29: + %t60 = call i32 @fn_is_id(ptr @.str145) + %t61 = icmp ne i32 %t60, 0 + %t62 = zext i1 %t61 to i32 + store i32 %t62, ptr %t49 + br label %scend30 +scend30: + %t63 = load i32, ptr %t49 + %t64 = icmp ne i32 %t63, 0 + %t65 = zext i1 %t64 to i32 + store i32 %t65, ptr %t48 + br i1 %t64, label %scend32, label %sc31 +sc31: + %t66 = call i32 @fn_is_id(ptr @.str146) + %t67 = icmp ne i32 %t66, 0 + %t68 = zext i1 %t67 to i32 + store i32 %t68, ptr %t48 + br label %scend32 +scend32: + %t69 = load i32, ptr %t48 + %t70 = icmp ne i32 %t69, 0 + br i1 %t70, label %then33, label %ifend35 +then33: + %t71 = load i32, ptr @g_pi + %t72 = add i32 %t71, 1 + store i32 %t72, ptr @g_pi + call void @fn_skip_clause() + br label %wcond3 +ifend35: + %t73 = call i32 @fn_is_id(ptr @.str147) + %t74 = icmp ne i32 %t73, 0 + br i1 %t74, label %then36, label %ifend38 +then36: + %t75 = load i32, ptr @g_pi + %t76 = add i32 %t75, 1 + store i32 %t76, ptr @g_pi + store i32 1, ptr %t13 + %t77 = call i32 @fn_is_op(ptr @.str148) + %t78 = icmp ne i32 %t77, 0 + br i1 %t78, label %then39, label %ifend41 +then39: + call void @fn_eat_op(ptr @.str149) + br label %wcond42 +wcond42: + %t79 = call i32 @fn_is_op(ptr @.str150) + %t80 = icmp eq i32 %t79, 0 + %t81 = zext i1 %t80 to i32 + %t82 = icmp ne i32 %t81, 0 + br i1 %t82, label %wbody43, label %wend44 +wbody43: + %t83 = call ptr @fn_node(i32 33) + store ptr %t83, ptr %t84 + %t85 = load ptr, ptr %t84 + %t86 = getelementptr inbounds %Str_Node, ptr %t85, i32 0, i32 1 + %t87 = call ptr @fn_eat_id() + store ptr %t87, ptr %t86 + %t88 = load ptr, ptr %t15 + %t89 = getelementptr inbounds %Str_Node, ptr %t88, i32 0, i32 7 + %t90 = load ptr, ptr %t89 + %t91 = getelementptr inbounds %LSlice, ptr %t90, i32 0, i32 1 + %t92 = getelementptr inbounds %LSlice, ptr %t90, i32 0, i32 2 + %t93 = getelementptr inbounds %LSlice, ptr %t90, i32 0, i32 0 + %t94 = load i32, ptr %t91 + %t95 = load i32, ptr %t92 + %t96 = icmp sge i32 %t94, %t95 + br i1 %t96, label %grow45, label %put46 +grow45: + %t97 = mul i32 %t95, 2 + %t98 = icmp eq i32 %t95, 0 + %t99 = select i1 %t98, i32 8, i32 %t97 + %t100 = getelementptr ptr, ptr null, i32 1 + %t101 = ptrtoint ptr %t100 to i64 + %t102 = zext i32 %t99 to i64 + %t103 = mul i64 %t102, %t101 + %t104 = load ptr, ptr %t93 + %t105 = call ptr @realloc(ptr %t104, i64 %t103) + store ptr %t105, ptr %t93 + store i32 %t99, ptr %t92 + br label %put46 +put46: + %t106 = load ptr, ptr %t84 + %t107 = load ptr, ptr %t93 + %t108 = getelementptr inbounds ptr, ptr %t107, i32 %t94 + store ptr %t106, ptr %t108 + %t109 = add i32 %t94, 1 + store i32 %t109, ptr %t91 + %t110 = call i32 @fn_is_op(ptr @.str151) + %t111 = icmp ne i32 %t110, 0 + br i1 %t111, label %then47, label %ifend49 +then47: + %t112 = load i32, ptr @g_pi + %t113 = add i32 %t112, 1 + store i32 %t113, ptr @g_pi + br label %ifend49 +ifend49: + br label %wcond42 +wend44: + call void @fn_eat_op(ptr @.str152) + br label %ifend41 +ifend41: + %t114 = load ptr, ptr %t15 + %t115 = getelementptr inbounds %Str_Node, ptr %t114, i32 0, i32 6 + %t116 = call ptr @fn_parse_query_tail() + store ptr %t116, ptr %t115 + %t117 = load ptr, ptr %t15 + %t118 = getelementptr inbounds %Str_Node, ptr %t117, i32 0, i32 5 + %t119 = load ptr, ptr %t15 + %t120 = getelementptr inbounds %Str_Node, ptr %t119, i32 0, i32 6 + %t121 = load ptr, ptr %t120 + %t122 = getelementptr inbounds %Str_Node, ptr %t121, i32 0, i32 4 + %t123 = load ptr, ptr %t122 + store ptr %t123, ptr %t118 + br label %wcond3 +ifend38: + br label %wend5 +wend5: + call void @fn_skipnl() + %t124 = call ptr @fn_block() + store ptr %t124, ptr %t125 + %t126 = load i32, ptr %t13 + %t127 = icmp ne i32 %t126, 0 + br i1 %t127, label %then50, label %else51 +then50: + %t128 = load ptr, ptr %t15 + %t129 = getelementptr inbounds %Str_Node, ptr %t128, i32 0, i32 4 + %t130 = load ptr, ptr %t125 + store ptr %t130, ptr %t129 + %t131 = call ptr @fn_node(i32 7) + store ptr %t131, ptr %t132 + %t133 = load ptr, ptr %t132 + %t134 = getelementptr inbounds %Str_Node, ptr %t133, i32 0, i32 7 + %t135 = load ptr, ptr %t134 + %t136 = getelementptr inbounds %LSlice, ptr %t135, i32 0, i32 1 + %t137 = getelementptr inbounds %LSlice, ptr %t135, i32 0, i32 2 + %t138 = getelementptr inbounds %LSlice, ptr %t135, i32 0, i32 0 + %t139 = load i32, ptr %t136 + %t140 = load i32, ptr %t137 + %t141 = icmp sge i32 %t139, %t140 + br i1 %t141, label %grow53, label %put54 +grow53: + %t142 = mul i32 %t140, 2 + %t143 = icmp eq i32 %t140, 0 + %t144 = select i1 %t143, i32 8, i32 %t142 + %t145 = getelementptr ptr, ptr null, i32 1 + %t146 = ptrtoint ptr %t145 to i64 + %t147 = zext i32 %t144 to i64 + %t148 = mul i64 %t147, %t146 + %t149 = load ptr, ptr %t138 + %t150 = call ptr @realloc(ptr %t149, i64 %t148) + store ptr %t150, ptr %t138 + store i32 %t144, ptr %t137 + br label %put54 +put54: + %t151 = load ptr, ptr %t15 + %t152 = load ptr, ptr %t138 + %t153 = getelementptr inbounds ptr, ptr %t152, i32 %t139 + store ptr %t151, ptr %t153 + %t154 = add i32 %t139, 1 + store i32 %t154, ptr %t136 + %t155 = load ptr, ptr %t7 + %t156 = getelementptr inbounds %Str_Node, ptr %t155, i32 0, i32 4 + %t157 = load ptr, ptr %t132 + store ptr %t157, ptr %t156 + br label %ifend52 +else51: + %t158 = load ptr, ptr %t7 + %t159 = getelementptr inbounds %Str_Node, ptr %t158, i32 0, i32 4 + %t160 = load ptr, ptr %t125 + store ptr %t160, ptr %t159 + br label %ifend52 +ifend52: + %t161 = load ptr, ptr %t7 + store ptr %t161, ptr %retval + br label %ret +ret: + %t162 = load ptr, ptr %retval + ret ptr %t162 +} + +define ptr @fn_parse_query_tail() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t11 = alloca ptr + %t40 = alloca ptr + call void @fn_eat_op(ptr @.str153) + %t0 = call ptr @fn_node(i32 7) + store ptr %t0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = call i32 @fn_is_op(ptr @.str154) + %t3 = icmp eq i32 %t2, 0 + %t4 = zext i1 %t3 to i32 + %t5 = icmp ne i32 %t4, 0 + br i1 %t5, label %wbody1, label %wend2 +wbody1: + %t6 = call i32 @fn_is_op(ptr @.str155) + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then3, label %else4 +then3: + %t8 = load i32, ptr @g_pi + %t9 = add i32 %t8, 1 + store i32 %t9, ptr @g_pi + %t10 = call ptr @fn_node(i32 33) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = call ptr @fn_eat_id() + store ptr %t14, ptr %t13 + %t15 = load ptr, ptr %t11 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 2 + store i32 1, ptr %t16 + %t17 = load ptr, ptr %t1 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 7 + %t19 = load ptr, ptr %t18 + %t20 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 1 + %t21 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 2 + %t22 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 0 + %t23 = load i32, ptr %t20 + %t24 = load i32, ptr %t21 + %t25 = icmp sge i32 %t23, %t24 + br i1 %t25, label %grow6, label %put7 +grow6: + %t26 = mul i32 %t24, 2 + %t27 = icmp eq i32 %t24, 0 + %t28 = select i1 %t27, i32 8, i32 %t26 + %t29 = getelementptr ptr, ptr null, i32 1 + %t30 = ptrtoint ptr %t29 to i64 + %t31 = zext i32 %t28 to i64 + %t32 = mul i64 %t31, %t30 + %t33 = load ptr, ptr %t22 + %t34 = call ptr @realloc(ptr %t33, i64 %t32) + store ptr %t34, ptr %t22 + store i32 %t28, ptr %t21 + br label %put7 +put7: + %t35 = load ptr, ptr %t11 + %t36 = load ptr, ptr %t22 + %t37 = getelementptr inbounds ptr, ptr %t36, i32 %t23 + store ptr %t35, ptr %t37 + %t38 = add i32 %t23, 1 + store i32 %t38, ptr %t20 + call void @fn_eat_op(ptr @.str156) + br label %ifend5 +else4: + %t39 = call ptr @fn_node(i32 33) + store ptr %t39, ptr %t40 + %t41 = load ptr, ptr %t40 + %t42 = getelementptr inbounds %Str_Node, ptr %t41, i32 0, i32 1 + %t43 = call ptr @fn_eat_id() + store ptr %t43, ptr %t42 + %t44 = load ptr, ptr %t40 + %t45 = getelementptr inbounds %Str_Node, ptr %t44, i32 0, i32 2 + store i32 0, ptr %t45 + %t46 = load ptr, ptr %t1 + %t47 = getelementptr inbounds %Str_Node, ptr %t46, i32 0, i32 7 + %t48 = load ptr, ptr %t47 + %t49 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 1 + %t50 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 2 + %t51 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 0 + %t52 = load i32, ptr %t49 + %t53 = load i32, ptr %t50 + %t54 = icmp sge i32 %t52, %t53 + br i1 %t54, label %grow8, label %put9 +grow8: + %t55 = mul i32 %t53, 2 + %t56 = icmp eq i32 %t53, 0 + %t57 = select i1 %t56, i32 8, i32 %t55 + %t58 = getelementptr ptr, ptr null, i32 1 + %t59 = ptrtoint ptr %t58 to i64 + %t60 = zext i32 %t57 to i64 + %t61 = mul i64 %t60, %t59 + %t62 = load ptr, ptr %t51 + %t63 = call ptr @realloc(ptr %t62, i64 %t61) + store ptr %t63, ptr %t51 + store i32 %t57, ptr %t50 + br label %put9 +put9: + %t64 = load ptr, ptr %t40 + %t65 = load ptr, ptr %t51 + %t66 = getelementptr inbounds ptr, ptr %t65, i32 %t52 + store ptr %t64, ptr %t66 + %t67 = add i32 %t52, 1 + store i32 %t67, ptr %t49 + br label %ifend5 +ifend5: + %t68 = call i32 @fn_is_op(ptr @.str157) + %t69 = icmp ne i32 %t68, 0 + br i1 %t69, label %then10, label %ifend12 +then10: + %t70 = load i32, ptr @g_pi + %t71 = add i32 %t70, 1 + store i32 %t71, ptr @g_pi + br label %ifend12 +ifend12: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str158) + %t72 = call i32 @fn_is_id(ptr @.str159) + %t73 = icmp ne i32 %t72, 0 + br i1 %t73, label %then13, label %ifend15 +then13: + %t74 = load i32, ptr @g_pi + %t75 = add i32 %t74, 1 + store i32 %t75, ptr @g_pi + %t76 = load ptr, ptr %t1 + %t77 = getelementptr inbounds %Str_Node, ptr %t76, i32 0, i32 4 + %t78 = call ptr @fn_expr() + store ptr %t78, ptr %t77 + br label %ifend15 +ifend15: + %t79 = load ptr, ptr %t1 + store ptr %t79, ptr %retval + br label %ret +ret: + %t80 = load ptr, ptr %retval + ret ptr %t80 +} + +define ptr @fn_parse_query_for() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t7 = alloca ptr + %t38 = alloca ptr + %t40 = alloca ptr + %t0 = call ptr @fn_node(i32 21) + store ptr %t0, ptr %t1 + call void @fn_eat_op(ptr @.str160) + br label %wcond0 +wcond0: + %t2 = call i32 @fn_is_op(ptr @.str161) + %t3 = icmp eq i32 %t2, 0 + %t4 = zext i1 %t3 to i32 + %t5 = icmp ne i32 %t4, 0 + br i1 %t5, label %wbody1, label %wend2 +wbody1: + %t6 = call ptr @fn_node(i32 33) + store ptr %t6, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds %Str_Node, ptr %t8, i32 0, i32 1 + %t10 = call ptr @fn_eat_id() + store ptr %t10, ptr %t9 + %t11 = load ptr, ptr %t1 + %t12 = getelementptr inbounds %Str_Node, ptr %t11, i32 0, i32 7 + %t13 = load ptr, ptr %t12 + %t14 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 1 + %t15 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 2 + %t16 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 0 + %t17 = load i32, ptr %t14 + %t18 = load i32, ptr %t15 + %t19 = icmp sge i32 %t17, %t18 + br i1 %t19, label %grow3, label %put4 +grow3: + %t20 = mul i32 %t18, 2 + %t21 = icmp eq i32 %t18, 0 + %t22 = select i1 %t21, i32 8, i32 %t20 + %t23 = getelementptr ptr, ptr null, i32 1 + %t24 = ptrtoint ptr %t23 to i64 + %t25 = zext i32 %t22 to i64 + %t26 = mul i64 %t25, %t24 + %t27 = load ptr, ptr %t16 + %t28 = call ptr @realloc(ptr %t27, i64 %t26) + store ptr %t28, ptr %t16 + store i32 %t22, ptr %t15 + br label %put4 +put4: + %t29 = load ptr, ptr %t7 + %t30 = load ptr, ptr %t16 + %t31 = getelementptr inbounds ptr, ptr %t30, i32 %t17 + store ptr %t29, ptr %t31 + %t32 = add i32 %t17, 1 + store i32 %t32, ptr %t14 + %t33 = call i32 @fn_is_op(ptr @.str162) + %t34 = icmp ne i32 %t33, 0 + br i1 %t34, label %then5, label %ifend7 +then5: + %t35 = load i32, ptr @g_pi + %t36 = add i32 %t35, 1 + store i32 %t36, ptr @g_pi + br label %ifend7 +ifend7: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str163) + %t37 = call ptr @fn_eat_id() + store ptr %t37, ptr %t38 + %t39 = call ptr @fn_eat_id() + store ptr %t39, ptr %t40 + %t41 = load ptr, ptr %t1 + %t42 = getelementptr inbounds %Str_Node, ptr %t41, i32 0, i32 6 + %t43 = call ptr @fn_parse_query_tail() + store ptr %t43, ptr %t42 + %t44 = load ptr, ptr %t1 + %t45 = getelementptr inbounds %Str_Node, ptr %t44, i32 0, i32 5 + %t46 = load ptr, ptr %t1 + %t47 = getelementptr inbounds %Str_Node, ptr %t46, i32 0, i32 6 + %t48 = load ptr, ptr %t47 + %t49 = getelementptr inbounds %Str_Node, ptr %t48, i32 0, i32 4 + %t50 = load ptr, ptr %t49 + store ptr %t50, ptr %t45 + %t51 = load ptr, ptr %t1 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 4 + %t53 = call ptr @fn_block() + store ptr %t53, ptr %t52 + %t54 = load ptr, ptr %t1 + store ptr %t54, ptr %retval + br label %ret +ret: + %t55 = load ptr, ptr %retval + ret ptr %t55 +} + +define ptr @fn_parse_spawn() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t11 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 22) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str164) + br label %wcond0 +wcond0: + %t7 = icmp ne i32 1, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + call void @fn_skipnl() + %t8 = call i32 @fn_is_op(ptr @.str165) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then3, label %ifend5 +then3: + br label %wend2 +ifend5: + %t10 = call ptr @fn_node(i32 42) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = call ptr @fn_eat_id() + store ptr %t14, ptr %t13 + call void @fn_eat_op(ptr @.str166) + %t15 = load ptr, ptr %t11 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 4 + %t17 = call ptr @fn_record() + store ptr %t17, ptr %t16 + %t18 = load ptr, ptr %t3 + %t19 = getelementptr inbounds %Str_Node, ptr %t18, i32 0, i32 7 + %t20 = load ptr, ptr %t19 + %t21 = getelementptr inbounds %LSlice, ptr %t20, i32 0, i32 1 + %t22 = getelementptr inbounds %LSlice, ptr %t20, i32 0, i32 2 + %t23 = getelementptr inbounds %LSlice, ptr %t20, i32 0, i32 0 + %t24 = load i32, ptr %t21 + %t25 = load i32, ptr %t22 + %t26 = icmp sge i32 %t24, %t25 + br i1 %t26, label %grow6, label %put7 +grow6: + %t27 = mul i32 %t25, 2 + %t28 = icmp eq i32 %t25, 0 + %t29 = select i1 %t28, i32 8, i32 %t27 + %t30 = getelementptr ptr, ptr null, i32 1 + %t31 = ptrtoint ptr %t30 to i64 + %t32 = zext i32 %t29 to i64 + %t33 = mul i64 %t32, %t31 + %t34 = load ptr, ptr %t23 + %t35 = call ptr @realloc(ptr %t34, i64 %t33) + store ptr %t35, ptr %t23 + store i32 %t29, ptr %t22 + br label %put7 +put7: + %t36 = load ptr, ptr %t11 + %t37 = load ptr, ptr %t23 + %t38 = getelementptr inbounds ptr, ptr %t37, i32 %t24 + store ptr %t36, ptr %t38 + %t39 = add i32 %t24, 1 + store i32 %t39, ptr %t21 + %t40 = call i32 @fn_is_op(ptr @.str167) + %t41 = icmp ne i32 %t40, 0 + br i1 %t41, label %then8, label %ifend10 +then8: + %t42 = load i32, ptr @g_pi + %t43 = add i32 %t42, 1 + store i32 %t43, ptr @g_pi + br label %ifend10 +ifend10: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str168) + %t44 = load ptr, ptr %t3 + store ptr %t44, ptr %retval + br label %ret +ret: + %t45 = load ptr, ptr %retval + ret ptr %t45 +} + +define ptr @fn_parse_archetype() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t11 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 10) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str169) + br label %wcond0 +wcond0: + %t7 = icmp ne i32 1, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + call void @fn_skipnl() + %t8 = call i32 @fn_is_op(ptr @.str170) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then3, label %ifend5 +then3: + br label %wend2 +ifend5: + %t10 = call ptr @fn_node(i32 33) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = call ptr @fn_eat_id() + store ptr %t14, ptr %t13 + %t15 = load ptr, ptr %t3 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 7 + %t17 = load ptr, ptr %t16 + %t18 = getelementptr inbounds %LSlice, ptr %t17, i32 0, i32 1 + %t19 = getelementptr inbounds %LSlice, ptr %t17, i32 0, i32 2 + %t20 = getelementptr inbounds %LSlice, ptr %t17, i32 0, i32 0 + %t21 = load i32, ptr %t18 + %t22 = load i32, ptr %t19 + %t23 = icmp sge i32 %t21, %t22 + br i1 %t23, label %grow6, label %put7 +grow6: + %t24 = mul i32 %t22, 2 + %t25 = icmp eq i32 %t22, 0 + %t26 = select i1 %t25, i32 8, i32 %t24 + %t27 = getelementptr ptr, ptr null, i32 1 + %t28 = ptrtoint ptr %t27 to i64 + %t29 = zext i32 %t26 to i64 + %t30 = mul i64 %t29, %t28 + %t31 = load ptr, ptr %t20 + %t32 = call ptr @realloc(ptr %t31, i64 %t30) + store ptr %t32, ptr %t20 + store i32 %t26, ptr %t19 + br label %put7 +put7: + %t33 = load ptr, ptr %t11 + %t34 = load ptr, ptr %t20 + %t35 = getelementptr inbounds ptr, ptr %t34, i32 %t21 + store ptr %t33, ptr %t35 + %t36 = add i32 %t21, 1 + store i32 %t36, ptr %t18 + %t37 = call i32 @fn_is_op(ptr @.str171) + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %then8, label %ifend10 +then8: + %t39 = load i32, ptr @g_pi + %t40 = add i32 %t39, 1 + store i32 %t40, ptr @g_pi + br label %ifend10 +ifend10: + call void @fn_skipnl() + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str172) + %t41 = load ptr, ptr %t3 + store ptr %t41, ptr %retval + br label %ret +ret: + %t42 = load ptr, ptr %retval + ret ptr %t42 +} + +define ptr @fn_parse_extern() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t5 = alloca ptr + %t14 = alloca ptr + %t62 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_eat_id() + store ptr %t2, ptr %t3 + %t4 = call ptr @fn_node(i32 11) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Node, ptr %t6, i32 0, i32 1 + %t8 = call ptr @fn_eat_id() + store ptr %t8, ptr %t7 + call void @fn_eat_op(ptr @.str173) + br label %wcond0 +wcond0: + %t9 = call i32 @fn_is_op(ptr @.str174) + %t10 = icmp eq i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %wbody1, label %wend2 +wbody1: + %t13 = call ptr @fn_node(i32 5) + store ptr %t13, ptr %t14 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 1 + %t17 = call ptr @fn_eat_id() + store ptr %t17, ptr %t16 + call void @fn_eat_op(ptr @.str175) + %t18 = load ptr, ptr %t14 + %t19 = getelementptr inbounds %Str_Node, ptr %t18, i32 0, i32 3 + %t20 = call ptr @fn_ptype() + store ptr %t20, ptr %t19 + %t21 = load ptr, ptr %t5 + %t22 = getelementptr inbounds %Str_Node, ptr %t21, i32 0, i32 7 + %t23 = load ptr, ptr %t22 + %t24 = getelementptr inbounds %LSlice, ptr %t23, i32 0, i32 1 + %t25 = getelementptr inbounds %LSlice, ptr %t23, i32 0, i32 2 + %t26 = getelementptr inbounds %LSlice, ptr %t23, i32 0, i32 0 + %t27 = load i32, ptr %t24 + %t28 = load i32, ptr %t25 + %t29 = icmp sge i32 %t27, %t28 + br i1 %t29, label %grow3, label %put4 +grow3: + %t30 = mul i32 %t28, 2 + %t31 = icmp eq i32 %t28, 0 + %t32 = select i1 %t31, i32 8, i32 %t30 + %t33 = getelementptr ptr, ptr null, i32 1 + %t34 = ptrtoint ptr %t33 to i64 + %t35 = zext i32 %t32 to i64 + %t36 = mul i64 %t35, %t34 + %t37 = load ptr, ptr %t26 + %t38 = call ptr @realloc(ptr %t37, i64 %t36) + store ptr %t38, ptr %t26 + store i32 %t32, ptr %t25 + br label %put4 +put4: + %t39 = load ptr, ptr %t14 + %t40 = load ptr, ptr %t26 + %t41 = getelementptr inbounds ptr, ptr %t40, i32 %t27 + store ptr %t39, ptr %t41 + %t42 = add i32 %t27, 1 + store i32 %t42, ptr %t24 + %t43 = call i32 @fn_is_op(ptr @.str176) + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then5, label %ifend7 +then5: + %t45 = load i32, ptr @g_pi + %t46 = add i32 %t45, 1 + store i32 %t46, ptr @g_pi + br label %ifend7 +ifend7: + br label %wcond0 +wend2: + call void @fn_eat_op(ptr @.str177) + %t47 = load ptr, ptr %t5 + %t48 = getelementptr inbounds %Str_Node, ptr %t47, i32 0, i32 3 + store ptr @.str178, ptr %t48 + %t49 = call i32 @fn_is_op(ptr @.str179) + %t50 = icmp ne i32 %t49, 0 + br i1 %t50, label %then8, label %ifend10 +then8: + %t51 = load i32, ptr @g_pi + %t52 = add i32 %t51, 1 + store i32 %t52, ptr @g_pi + %t53 = load ptr, ptr %t5 + %t54 = getelementptr inbounds %Str_Node, ptr %t53, i32 0, i32 3 + %t55 = call ptr @fn_ptype() + store ptr %t55, ptr %t54 + br label %ifend10 +ifend10: + call void @fn_eat_op(ptr @.str180) + %t56 = load ptr, ptr @g_toks + %t57 = getelementptr inbounds %LSlice, ptr %t56, i32 0, i32 0 + %t58 = load ptr, ptr %t57 + %t59 = load i32, ptr @g_pi + %t60 = getelementptr inbounds ptr, ptr %t58, i32 %t59 + %t61 = load ptr, ptr %t60 + store ptr %t61, ptr %t62 + %t63 = load ptr, ptr %t5 + %t64 = getelementptr inbounds %Str_Node, ptr %t63, i32 0, i32 4 + %t65 = call ptr @fn_node(i32 31) + store ptr %t65, ptr %t64 + %t66 = load ptr, ptr %t5 + %t67 = getelementptr inbounds %Str_Node, ptr %t66, i32 0, i32 4 + %t68 = load ptr, ptr %t67 + %t69 = getelementptr inbounds %Str_Node, ptr %t68, i32 0, i32 1 + %t70 = load ptr, ptr %t62 + %t71 = getelementptr inbounds %Str_Tok, ptr %t70, i32 0, i32 1 + %t72 = load ptr, ptr %t71 + store ptr %t72, ptr %t69 + %t73 = load i32, ptr @g_pi + %t74 = add i32 %t73, 1 + store i32 %t74, ptr @g_pi + %t75 = load ptr, ptr %t5 + store ptr %t75, ptr %retval + br label %ret +ret: + %t76 = load ptr, ptr %retval + ret ptr %t76 +} + +define ptr @fn_parse_widget() { +entry: + %retval = alloca ptr + %t1 = alloca ptr + %t8 = alloca i32 + %t9 = alloca i32 + %t53 = alloca ptr + %t0 = call ptr @fn_node(i32 12) + store ptr %t0, ptr %t1 + %t2 = load ptr, ptr %t1 + %t3 = getelementptr inbounds %Str_Node, ptr %t2, i32 0, i32 1 + %t4 = call ptr @fn_eat_id() + store ptr %t4, ptr %t3 + %t5 = load ptr, ptr %t1 + %t6 = getelementptr inbounds %Str_Node, ptr %t5, i32 0, i32 5 + %t7 = call ptr @fn_node(i32 7) + store ptr %t7, ptr %t6 + br label %wcond0 +wcond0: + %t10 = load ptr, ptr @g_toks + %t11 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 0 + %t12 = load ptr, ptr %t11 + %t13 = load i32, ptr @g_pi + %t14 = getelementptr inbounds ptr, ptr %t12, i32 %t13 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %Str_Tok, ptr %t15, i32 0, i32 0 + %t17 = load i32, ptr %t16 + %t18 = icmp eq i32 %t17, 0 + %t19 = zext i1 %t18 to i32 + %t20 = icmp ne i32 %t19, 0 + %t21 = zext i1 %t20 to i32 + store i32 %t21, ptr %t9 + br i1 %t20, label %sc3, label %scend4 +sc3: + %t22 = load ptr, ptr @g_toks + %t23 = getelementptr inbounds %LSlice, ptr %t22, i32 0, i32 0 + %t24 = load ptr, ptr %t23 + %t25 = load i32, ptr @g_pi + %t26 = add i32 %t25, 1 + %t27 = getelementptr inbounds ptr, ptr %t24, i32 %t26 + %t28 = load ptr, ptr %t27 + %t29 = getelementptr inbounds %Str_Tok, ptr %t28, i32 0, i32 0 + %t30 = load i32, ptr %t29 + %t31 = icmp eq i32 %t30, 3 + %t32 = zext i1 %t31 to i32 + %t33 = icmp ne i32 %t32, 0 + %t34 = zext i1 %t33 to i32 + store i32 %t34, ptr %t9 + br label %scend4 +scend4: + %t35 = load i32, ptr %t9 + %t36 = icmp ne i32 %t35, 0 + %t37 = zext i1 %t36 to i32 + store i32 %t37, ptr %t8 + br i1 %t36, label %sc5, label %scend6 +sc5: + %t38 = load ptr, ptr @g_toks + %t39 = getelementptr inbounds %LSlice, ptr %t38, i32 0, i32 0 + %t40 = load ptr, ptr %t39 + %t41 = load i32, ptr @g_pi + %t42 = add i32 %t41, 1 + %t43 = getelementptr inbounds ptr, ptr %t40, i32 %t42 + %t44 = load ptr, ptr %t43 + %t45 = getelementptr inbounds %Str_Tok, ptr %t44, i32 0, i32 1 + %t46 = load ptr, ptr %t45 + %t47 = call i32 @fn_streq(ptr %t46, ptr @.str181) + %t48 = icmp ne i32 %t47, 0 + %t49 = zext i1 %t48 to i32 + store i32 %t49, ptr %t8 + br label %scend6 +scend6: + %t50 = load i32, ptr %t8 + %t51 = icmp ne i32 %t50, 0 + br i1 %t51, label %wbody1, label %wend2 +wbody1: + %t52 = call ptr @fn_node(i32 42) + store ptr %t52, ptr %t53 + %t54 = load ptr, ptr %t53 + %t55 = getelementptr inbounds %Str_Node, ptr %t54, i32 0, i32 1 + %t56 = call ptr @fn_eat_id() + store ptr %t56, ptr %t55 + call void @fn_eat_op(ptr @.str182) + %t57 = load ptr, ptr %t53 + %t58 = getelementptr inbounds %Str_Node, ptr %t57, i32 0, i32 4 + %t59 = call ptr @fn_expr() + store ptr %t59, ptr %t58 + %t60 = load ptr, ptr %t1 + %t61 = getelementptr inbounds %Str_Node, ptr %t60, i32 0, i32 5 + %t62 = load ptr, ptr %t61 + %t63 = getelementptr inbounds %Str_Node, ptr %t62, i32 0, i32 7 + %t64 = load ptr, ptr %t63 + %t65 = getelementptr inbounds %LSlice, ptr %t64, i32 0, i32 1 + %t66 = getelementptr inbounds %LSlice, ptr %t64, i32 0, i32 2 + %t67 = getelementptr inbounds %LSlice, ptr %t64, i32 0, i32 0 + %t68 = load i32, ptr %t65 + %t69 = load i32, ptr %t66 + %t70 = icmp sge i32 %t68, %t69 + br i1 %t70, label %grow7, label %put8 +grow7: + %t71 = mul i32 %t69, 2 + %t72 = icmp eq i32 %t69, 0 + %t73 = select i1 %t72, i32 8, i32 %t71 + %t74 = getelementptr ptr, ptr null, i32 1 + %t75 = ptrtoint ptr %t74 to i64 + %t76 = zext i32 %t73 to i64 + %t77 = mul i64 %t76, %t75 + %t78 = load ptr, ptr %t67 + %t79 = call ptr @realloc(ptr %t78, i64 %t77) + store ptr %t79, ptr %t67 + store i32 %t73, ptr %t66 + br label %put8 +put8: + %t80 = load ptr, ptr %t53 + %t81 = load ptr, ptr %t67 + %t82 = getelementptr inbounds ptr, ptr %t81, i32 %t68 + store ptr %t80, ptr %t82 + %t83 = add i32 %t68, 1 + store i32 %t83, ptr %t65 + br label %wcond0 +wend2: + call void @fn_skipnl() + %t84 = call i32 @fn_is_op(ptr @.str183) + %t85 = icmp ne i32 %t84, 0 + br i1 %t85, label %then9, label %ifend11 +then9: + %t86 = load i32, ptr @g_pi + %t87 = add i32 %t86, 1 + store i32 %t87, ptr @g_pi + br label %wcond12 +wcond12: + %t88 = icmp ne i32 1, 0 + br i1 %t88, label %wbody13, label %wend14 +wbody13: + call void @fn_skipnl() + %t89 = call i32 @fn_is_op(ptr @.str184) + %t90 = icmp ne i32 %t89, 0 + br i1 %t90, label %then15, label %ifend17 +then15: + br label %wend14 +ifend17: + %t91 = load ptr, ptr %t1 + %t92 = getelementptr inbounds %Str_Node, ptr %t91, i32 0, i32 7 + %t93 = load ptr, ptr %t92 + %t94 = getelementptr inbounds %LSlice, ptr %t93, i32 0, i32 1 + %t95 = getelementptr inbounds %LSlice, ptr %t93, i32 0, i32 2 + %t96 = getelementptr inbounds %LSlice, ptr %t93, i32 0, i32 0 + %t97 = load i32, ptr %t94 + %t98 = load i32, ptr %t95 + %t99 = icmp sge i32 %t97, %t98 + br i1 %t99, label %grow18, label %put19 +grow18: + %t100 = mul i32 %t98, 2 + %t101 = icmp eq i32 %t98, 0 + %t102 = select i1 %t101, i32 8, i32 %t100 + %t103 = getelementptr ptr, ptr null, i32 1 + %t104 = ptrtoint ptr %t103 to i64 + %t105 = zext i32 %t102 to i64 + %t106 = mul i64 %t105, %t104 + %t107 = load ptr, ptr %t96 + %t108 = call ptr @realloc(ptr %t107, i64 %t106) + store ptr %t108, ptr %t96 + store i32 %t102, ptr %t95 + br label %put19 +put19: + %t109 = call ptr @fn_parse_widget() + %t110 = load ptr, ptr %t96 + %t111 = getelementptr inbounds ptr, ptr %t110, i32 %t97 + store ptr %t109, ptr %t111 + %t112 = add i32 %t97, 1 + store i32 %t112, ptr %t94 + br label %wcond12 +wend14: + call void @fn_eat_op(ptr @.str185) + br label %ifend11 +ifend11: + %t113 = load ptr, ptr %t1 + store ptr %t113, ptr %retval + br label %ret +ret: + %t114 = load ptr, ptr %retval + ret ptr %t114 +} + +define ptr @fn_parse_ui() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t0 = load i32, ptr @g_pi + %t1 = add i32 %t0, 1 + store i32 %t1, ptr @g_pi + %t2 = call ptr @fn_node(i32 12) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 1 + %t6 = call ptr @fn_eat_id() + store ptr %t6, ptr %t5 + %t7 = load ptr, ptr %t3 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 2 + store i32 1, ptr %t8 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str186) + call void @fn_skipnl() + %t9 = load ptr, ptr %t3 + %t10 = getelementptr inbounds %Str_Node, ptr %t9, i32 0, i32 4 + %t11 = call ptr @fn_parse_widget() + store ptr %t11, ptr %t10 + call void @fn_skipnl() + call void @fn_eat_op(ptr @.str187) + %t12 = load ptr, ptr %t3 + store ptr %t12, ptr %retval + br label %ret +ret: + %t13 = load ptr, ptr %retval + ret ptr %t13 +} + +define ptr @fn_val(ptr %arg_code, ptr %arg_ty) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t7 = alloca ptr + store ptr %arg_code, ptr %t0 + store ptr %arg_ty, ptr %t1 + %t2 = getelementptr %Str_Val, ptr null, i32 1 + %t3 = ptrtoint ptr %t2 to i64 + %t4 = call ptr @malloc(i64 %t3) + %t5 = getelementptr inbounds %Str_Val, ptr %t4, i32 0, i32 0 + store ptr null, ptr %t5 + %t6 = getelementptr inbounds %Str_Val, ptr %t4, i32 0, i32 1 + store ptr null, ptr %t6 + store ptr %t4, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds %Str_Val, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t0 + store ptr %t10, ptr %t9 + %t11 = load ptr, ptr %t7 + %t12 = getelementptr inbounds %Str_Val, ptr %t11, i32 0, i32 1 + %t13 = load ptr, ptr %t1 + store ptr %t13, ptr %t12 + %t14 = load ptr, ptr %t7 + store ptr %t14, ptr %retval + br label %ret +ret: + %t15 = load ptr, ptr %retval + ret ptr %t15 +} + +define void @fn_emit(ptr %arg_s) { +entry: + %t0 = alloca ptr + store ptr %arg_s, ptr %t0 + %t1 = load ptr, ptr @g_code + %t2 = load ptr, ptr %t0 + call void @fn_buf_puts(ptr %t1, ptr %t2) + br label %ret +ret: + ret void +} + +define void @fn_emith(ptr %arg_s) { +entry: + %t0 = alloca ptr + store ptr %arg_s, ptr %t0 + %t1 = load ptr, ptr @g_head + %t2 = load ptr, ptr %t0 + call void @fn_buf_puts(ptr %t1, ptr %t2) + br label %ret +ret: + ret void +} + +define ptr @fn_emit_alloca(ptr %arg_llt) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t4 = alloca ptr + store ptr %arg_llt, ptr %t0 + %t1 = load i32, ptr @g_ll_t + %t2 = call ptr @fn_itoa(i32 %t1) + %t3 = call ptr @fn_sconcat(ptr @.str188, ptr %t2) + store ptr %t3, ptr %t4 + %t5 = load i32, ptr @g_ll_t + %t6 = add i32 %t5, 1 + store i32 %t6, ptr @g_ll_t + %t7 = load ptr, ptr @g_falloc + call void @fn_buf_puts(ptr %t7, ptr @.str189) + %t8 = load ptr, ptr @g_falloc + %t9 = load ptr, ptr %t4 + call void @fn_buf_puts(ptr %t8, ptr %t9) + %t10 = load ptr, ptr @g_falloc + call void @fn_buf_puts(ptr %t10, ptr @.str190) + %t11 = load ptr, ptr @g_falloc + %t12 = load ptr, ptr %t0 + call void @fn_buf_puts(ptr %t11, ptr %t12) + %t13 = load ptr, ptr @g_falloc + call void @fn_buf_puts(ptr %t13, ptr @.str191) + %t14 = load ptr, ptr %t4 + store ptr %t14, ptr %retval + br label %ret +ret: + %t15 = load ptr, ptr %retval + ret ptr %t15 +} + +define ptr @fn_sconcat(ptr %arg_a, ptr %arg_b) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t4 = alloca i32 + %t7 = alloca i32 + %t14 = alloca ptr + %t15 = alloca i32 + %t32 = alloca i32 + store ptr %arg_a, ptr %t0 + store ptr %arg_b, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = call i32 @fn_slen(ptr %t2) + store i32 %t3, ptr %t4 + %t5 = load ptr, ptr %t1 + %t6 = call i32 @fn_slen(ptr %t5) + store i32 %t6, ptr %t7 + %t8 = load i32, ptr %t4 + %t9 = load i32, ptr %t7 + %t10 = add i32 %t8, %t9 + %t11 = add i32 %t10, 1 + %t12 = zext i32 %t11 to i64 + %t13 = call ptr @malloc(i64 %t12) + store ptr %t13, ptr %t14 + store i32 0, ptr %t15 + br label %wcond0 +wcond0: + %t16 = load i32, ptr %t15 + %t17 = load i32, ptr %t4 + %t18 = icmp slt i32 %t16, %t17 + %t19 = zext i1 %t18 to i32 + %t20 = icmp ne i32 %t19, 0 + br i1 %t20, label %wbody1, label %wend2 +wbody1: + %t21 = load ptr, ptr %t14 + %t22 = load i32, ptr %t15 + %t23 = load ptr, ptr %t0 + %t24 = load i32, ptr %t15 + %t25 = getelementptr inbounds i8, ptr %t23, i32 %t24 + %t26 = load i8, ptr %t25 + %t27 = zext i8 %t26 to i32 + %t28 = getelementptr inbounds i8, ptr %t21, i32 %t22 + %t29 = trunc i32 %t27 to i8 + store i8 %t29, ptr %t28 + %t30 = load i32, ptr %t15 + %t31 = add i32 %t30, 1 + store i32 %t31, ptr %t15 + br label %wcond0 +wend2: + store i32 0, ptr %t32 + br label %wcond3 +wcond3: + %t33 = load i32, ptr %t32 + %t34 = load i32, ptr %t7 + %t35 = icmp slt i32 %t33, %t34 + %t36 = zext i1 %t35 to i32 + %t37 = icmp ne i32 %t36, 0 + br i1 %t37, label %wbody4, label %wend5 +wbody4: + %t38 = load ptr, ptr %t14 + %t39 = load i32, ptr %t4 + %t40 = load i32, ptr %t32 + %t41 = add i32 %t39, %t40 + %t42 = load ptr, ptr %t1 + %t43 = load i32, ptr %t32 + %t44 = getelementptr inbounds i8, ptr %t42, i32 %t43 + %t45 = load i8, ptr %t44 + %t46 = zext i8 %t45 to i32 + %t47 = getelementptr inbounds i8, ptr %t38, i32 %t41 + %t48 = trunc i32 %t46 to i8 + store i8 %t48, ptr %t47 + %t49 = load i32, ptr %t32 + %t50 = add i32 %t49, 1 + store i32 %t50, ptr %t32 + br label %wcond3 +wend5: + %t51 = load ptr, ptr %t14 + %t52 = load i32, ptr %t4 + %t53 = load i32, ptr %t7 + %t54 = add i32 %t52, %t53 + %t55 = getelementptr inbounds i8, ptr %t51, i32 %t54 + %t56 = trunc i32 0 to i8 + store i8 %t56, ptr %t55 + %t57 = load ptr, ptr %t14 + store ptr %t57, ptr %retval + br label %ret +ret: + %t58 = load ptr, ptr %retval + ret ptr %t58 +} + +define ptr @fn_nreg() { +entry: + %retval = alloca ptr + %t3 = alloca ptr + %t0 = load i32, ptr @g_ll_t + %t1 = call ptr @fn_itoa(i32 %t0) + %t2 = call ptr @fn_sconcat(ptr @.str192, ptr %t1) + store ptr %t2, ptr %t3 + %t4 = load i32, ptr @g_ll_t + %t5 = add i32 %t4, 1 + store i32 %t5, ptr @g_ll_t + %t6 = load ptr, ptr %t3 + store ptr %t6, ptr %retval + br label %ret +ret: + %t7 = load ptr, ptr %retval + ret ptr %t7 +} + +define ptr @fn_lbl(ptr %arg_pfx) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t5 = alloca ptr + store ptr %arg_pfx, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = load i32, ptr @g_ll_lbl + %t3 = call ptr @fn_itoa(i32 %t2) + %t4 = call ptr @fn_sconcat(ptr %t1, ptr %t3) + store ptr %t4, ptr %t5 + %t6 = load i32, ptr @g_ll_lbl + %t7 = add i32 %t6, 1 + store i32 %t7, ptr @g_ll_lbl + %t8 = load ptr, ptr %t5 + store ptr %t8, ptr %retval + br label %ret +ret: + %t9 = load ptr, ptr %retval + ret ptr %t9 +} + +define ptr @fn_llty(ptr %arg_t) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + store ptr %arg_t, ptr %t0 + %t3 = load ptr, ptr %t0 + %t4 = call i32 @fn_streq(ptr %t3, ptr @.str193) + %t5 = icmp ne i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %t2 + br i1 %t5, label %scend1, label %sc0 +sc0: + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str194) + %t9 = icmp ne i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + store i32 %t10, ptr %t2 + br label %scend1 +scend1: + %t11 = load i32, ptr %t2 + %t12 = icmp ne i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + store i32 %t13, ptr %t1 + br i1 %t12, label %scend3, label %sc2 +sc2: + %t14 = load ptr, ptr %t0 + %t15 = call i32 @fn_streq(ptr %t14, ptr @.str195) + %t16 = icmp ne i32 %t15, 0 + %t17 = zext i1 %t16 to i32 + store i32 %t17, ptr %t1 + br label %scend3 +scend3: + %t18 = load i32, ptr %t1 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then4, label %ifend6 +then4: + store ptr @.str196, ptr %retval + br label %ret +ifend6: + %t20 = load ptr, ptr %t0 + %t21 = call i32 @fn_streq(ptr %t20, ptr @.str197) + %t22 = icmp ne i32 %t21, 0 + br i1 %t22, label %then7, label %ifend9 +then7: + store ptr @.str198, ptr %retval + br label %ret +ifend9: + store ptr @.str199, ptr %retval + br label %ret +ret: + %t23 = load ptr, ptr %retval + ret ptr %t23 +} + +define i32 @fn_is_slice_ty(ptr %arg_t) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_t, ptr %t0 + %t2 = load ptr, ptr %t0 + %t3 = getelementptr inbounds i8, ptr %t2, i32 0 + %t4 = load i8, ptr %t3 + %t5 = zext i8 %t4 to i32 + %t6 = icmp eq i32 %t5, 91 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t1 + br i1 %t8, label %sc0, label %scend1 +sc0: + %t10 = load ptr, ptr %t0 + %t11 = getelementptr inbounds i8, ptr %t10, i32 1 + %t12 = load i8, ptr %t11 + %t13 = zext i8 %t12 to i32 + %t14 = icmp eq i32 %t13, 93 + %t15 = zext i1 %t14 to i32 + %t16 = icmp ne i32 %t15, 0 + %t17 = zext i1 %t16 to i32 + store i32 %t17, ptr %t1 + br label %scend1 +scend1: + %t18 = load i32, ptr %t1 + store i32 %t18, ptr %retval + br label %ret +ret: + %t19 = load i32, ptr %retval + ret i32 %t19 +} + +define ptr @fn_slice_elem(ptr %arg_t) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + store ptr %arg_t, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = load ptr, ptr %t0 + %t3 = call i32 @fn_slen(ptr %t2) + %t4 = sub i32 %t3, 2 + %t5 = call ptr @fn_substr(ptr %t1, i32 2, i32 %t4) + store ptr %t5, ptr %retval + br label %ret +ret: + %t6 = load ptr, ptr %retval + ret ptr %t6 +} + +define ptr @fn_find_struct(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t15 = alloca ptr + %t16 = alloca i32 + store ptr %arg_name, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_prog + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %t15 + %t17 = load ptr, ptr %t15 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 0 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t16 + br i1 %t22, label %sc3, label %scend4 +sc3: + %t24 = load ptr, ptr %t15 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 1 + %t26 = load ptr, ptr %t25 + %t27 = load ptr, ptr %t0 + %t28 = call i32 @fn_streq(ptr %t26, ptr %t27) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t16 + br label %scend4 +scend4: + %t31 = load i32, ptr %t16 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then5, label %ifend7 +then5: + %t33 = load ptr, ptr %t15 + store ptr %t33, ptr %retval + br label %ret +ifend7: + %t34 = load i32, ptr %t1 + %t35 = add i32 %t34, 1 + store i32 %t35, ptr %t1 + br label %wcond0 +wend2: + store ptr null, ptr %retval + br label %ret +ret: + %t36 = load ptr, ptr %retval + ret ptr %t36 +} + +define i32 @fn_is_struct_ty(ptr %arg_t) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + store ptr %arg_t, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call ptr @fn_find_struct(ptr %t1) + %t3 = icmp eq ptr %t2, null + %t4 = zext i1 %t3 to i32 + %t5 = icmp eq i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %retval + br label %ret +ret: + %t7 = load i32, ptr %retval + ret i32 %t7 +} + +define ptr @fn_find_arch(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t15 = alloca ptr + %t16 = alloca i32 + store ptr %arg_name, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_prog + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %t15 + %t17 = load ptr, ptr %t15 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 10 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t16 + br i1 %t22, label %sc3, label %scend4 +sc3: + %t24 = load ptr, ptr %t15 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 1 + %t26 = load ptr, ptr %t25 + %t27 = load ptr, ptr %t0 + %t28 = call i32 @fn_streq(ptr %t26, ptr %t27) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t16 + br label %scend4 +scend4: + %t31 = load i32, ptr %t16 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then5, label %ifend7 +then5: + %t33 = load ptr, ptr %t15 + store ptr %t33, ptr %retval + br label %ret +ifend7: + %t34 = load i32, ptr %t1 + %t35 = add i32 %t34, 1 + store i32 %t35, ptr %t1 + br label %wcond0 +wend2: + store ptr null, ptr %retval + br label %ret +ret: + %t36 = load ptr, ptr %retval + ret ptr %t36 +} + +define ptr @fn_find_comp(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t15 = alloca ptr + %t16 = alloca i32 + store ptr %arg_name, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_prog + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %t15 + %t17 = load ptr, ptr %t15 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 8 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t16 + br i1 %t22, label %sc3, label %scend4 +sc3: + %t24 = load ptr, ptr %t15 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 1 + %t26 = load ptr, ptr %t25 + %t27 = load ptr, ptr %t0 + %t28 = call i32 @fn_streq(ptr %t26, ptr %t27) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t16 + br label %scend4 +scend4: + %t31 = load i32, ptr %t16 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then5, label %ifend7 +then5: + %t33 = load ptr, ptr %t15 + store ptr %t33, ptr %retval + br label %ret +ifend7: + %t34 = load i32, ptr %t1 + %t35 = add i32 %t34, 1 + store i32 %t35, ptr %t1 + br label %wcond0 +wend2: + store ptr null, ptr %retval + br label %ret +ret: + %t36 = load ptr, ptr %retval + ret ptr %t36 +} + +define ptr @fn_layout_node(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t3 = alloca ptr + store ptr %arg_name, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call ptr @fn_find_struct(ptr %t1) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = icmp eq ptr %t4, null + %t6 = zext i1 %t5 to i32 + %t7 = icmp eq i32 %t6, 0 + %t8 = zext i1 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then0, label %ifend2 +then0: + %t10 = load ptr, ptr %t3 + store ptr %t10, ptr %retval + br label %ret +ifend2: + %t11 = load ptr, ptr %t0 + %t12 = call ptr @fn_find_comp(ptr %t11) + store ptr %t12, ptr %retval + br label %ret +ret: + %t13 = load ptr, ptr %retval + ret ptr %t13 +} + +define ptr @fn_layout_ty(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + store ptr %arg_name, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call ptr @fn_find_struct(ptr %t1) + %t3 = icmp eq ptr %t2, null + %t4 = zext i1 %t3 to i32 + %t5 = icmp eq i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + %t8 = load ptr, ptr %t0 + %t9 = call ptr @fn_sconcat(ptr @.str200, ptr %t8) + store ptr %t9, ptr %retval + br label %ret +ifend2: + %t10 = load ptr, ptr %t0 + %t11 = call ptr @fn_sconcat(ptr @.str201, ptr %t10) + store ptr %t11, ptr %retval + br label %ret +ret: + %t12 = load ptr, ptr %retval + ret ptr %t12 +} + +define i32 @fn_field_index(ptr %arg_s, ptr %arg_fname) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + store ptr %arg_s, ptr %t0 + store ptr %arg_fname, ptr %t1 + store i32 0, ptr %t2 + br label %wcond0 +wcond0: + %t3 = load i32, ptr %t2 + %t4 = load ptr, ptr %t0 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 7 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %LSlice, ptr %t6, i32 0, i32 1 + %t8 = load i32, ptr %t7 + %t9 = icmp slt i32 %t3, %t8 + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %wbody1, label %wend2 +wbody1: + %t12 = load ptr, ptr %t0 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 7 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 0 + %t16 = load ptr, ptr %t15 + %t17 = load i32, ptr %t2 + %t18 = getelementptr inbounds ptr, ptr %t16, i32 %t17 + %t19 = load ptr, ptr %t18 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 1 + %t21 = load ptr, ptr %t20 + %t22 = load ptr, ptr %t1 + %t23 = call i32 @fn_streq(ptr %t21, ptr %t22) + %t24 = icmp ne i32 %t23, 0 + br i1 %t24, label %then3, label %ifend5 +then3: + %t25 = load i32, ptr %t2 + store i32 %t25, ptr %retval + br label %ret +ifend5: + %t26 = load i32, ptr %t2 + %t27 = add i32 %t26, 1 + store i32 %t27, ptr %t2 + br label %wcond0 +wend2: + %t28 = sub i32 0, 1 + store i32 %t28, ptr %retval + br label %ret +ret: + %t29 = load i32, ptr %retval + ret i32 %t29 +} + +define ptr @fn_field_type(ptr %arg_s, ptr %arg_fname) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + store ptr %arg_s, ptr %t0 + store ptr %arg_fname, ptr %t1 + store i32 0, ptr %t2 + br label %wcond0 +wcond0: + %t3 = load i32, ptr %t2 + %t4 = load ptr, ptr %t0 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 7 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %LSlice, ptr %t6, i32 0, i32 1 + %t8 = load i32, ptr %t7 + %t9 = icmp slt i32 %t3, %t8 + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %wbody1, label %wend2 +wbody1: + %t12 = load ptr, ptr %t0 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 7 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 0 + %t16 = load ptr, ptr %t15 + %t17 = load i32, ptr %t2 + %t18 = getelementptr inbounds ptr, ptr %t16, i32 %t17 + %t19 = load ptr, ptr %t18 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 1 + %t21 = load ptr, ptr %t20 + %t22 = load ptr, ptr %t1 + %t23 = call i32 @fn_streq(ptr %t21, ptr %t22) + %t24 = icmp ne i32 %t23, 0 + br i1 %t24, label %then3, label %ifend5 +then3: + %t25 = load ptr, ptr %t0 + %t26 = getelementptr inbounds %Str_Node, ptr %t25, i32 0, i32 7 + %t27 = load ptr, ptr %t26 + %t28 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 0 + %t29 = load ptr, ptr %t28 + %t30 = load i32, ptr %t2 + %t31 = getelementptr inbounds ptr, ptr %t29, i32 %t30 + %t32 = load ptr, ptr %t31 + %t33 = getelementptr inbounds %Str_Node, ptr %t32, i32 0, i32 3 + %t34 = load ptr, ptr %t33 + store ptr %t34, ptr %retval + br label %ret +ifend5: + %t35 = load i32, ptr %t2 + %t36 = add i32 %t35, 1 + store i32 %t36, ptr %t2 + br label %wcond0 +wend2: + store ptr @.str202, ptr %retval + br label %ret +ret: + %t37 = load ptr, ptr %retval + ret ptr %t37 +} + +define ptr @fn_find_global(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t15 = alloca ptr + %t16 = alloca i32 + %t34 = alloca i32 + store ptr %arg_name, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_prog + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %t15 + %t17 = load ptr, ptr %t15 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 2 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t16 + br i1 %t22, label %sc3, label %scend4 +sc3: + %t24 = load ptr, ptr %t15 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 1 + %t26 = load ptr, ptr %t25 + %t27 = load ptr, ptr %t0 + %t28 = call i32 @fn_streq(ptr %t26, ptr %t27) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t16 + br label %scend4 +scend4: + %t31 = load i32, ptr %t16 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then5, label %ifend7 +then5: + %t33 = load ptr, ptr %t15 + store ptr %t33, ptr %retval + br label %ret +ifend7: + %t35 = load ptr, ptr %t15 + %t36 = getelementptr inbounds %Str_Node, ptr %t35, i32 0, i32 0 + %t37 = load i32, ptr %t36 + %t38 = icmp eq i32 %t37, 3 + %t39 = zext i1 %t38 to i32 + %t40 = icmp ne i32 %t39, 0 + %t41 = zext i1 %t40 to i32 + store i32 %t41, ptr %t34 + br i1 %t40, label %sc8, label %scend9 +sc8: + %t42 = load ptr, ptr %t15 + %t43 = getelementptr inbounds %Str_Node, ptr %t42, i32 0, i32 1 + %t44 = load ptr, ptr %t43 + %t45 = load ptr, ptr %t0 + %t46 = call i32 @fn_streq(ptr %t44, ptr %t45) + %t47 = icmp ne i32 %t46, 0 + %t48 = zext i1 %t47 to i32 + store i32 %t48, ptr %t34 + br label %scend9 +scend9: + %t49 = load i32, ptr %t34 + %t50 = icmp ne i32 %t49, 0 + br i1 %t50, label %then10, label %ifend12 +then10: + %t51 = load ptr, ptr %t15 + store ptr %t51, ptr %retval + br label %ret +ifend12: + %t52 = load i32, ptr %t1 + %t53 = add i32 %t52, 1 + store i32 %t53, ptr %t1 + br label %wcond0 +wend2: + store ptr null, ptr %retval + br label %ret +ret: + %t54 = load ptr, ptr %retval + ret ptr %t54 +} + +define ptr @fn_find_fn(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t15 = alloca ptr + %t16 = alloca i32 + store ptr %arg_name, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_prog + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %t15 + %t17 = load ptr, ptr %t15 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 4 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t16 + br i1 %t22, label %sc3, label %scend4 +sc3: + %t24 = load ptr, ptr %t15 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 1 + %t26 = load ptr, ptr %t25 + %t27 = load ptr, ptr %t0 + %t28 = call i32 @fn_streq(ptr %t26, ptr %t27) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t16 + br label %scend4 +scend4: + %t31 = load i32, ptr %t16 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then5, label %ifend7 +then5: + %t33 = load ptr, ptr %t15 + store ptr %t33, ptr %retval + br label %ret +ifend7: + %t34 = load i32, ptr %t1 + %t35 = add i32 %t34, 1 + store i32 %t35, ptr %t1 + br label %wcond0 +wend2: + store ptr null, ptr %retval + br label %ret +ret: + %t36 = load ptr, ptr %retval + ret ptr %t36 +} + +define void @fn_loc_reset() { +entry: + store i32 0, ptr @g_nloc + br label %ret +ret: + ret void +} + +define void @fn_loc_push(ptr %arg_name, ptr %arg_r, ptr %arg_ty) { +entry: + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca ptr + store ptr %arg_name, ptr %t0 + store ptr %arg_r, ptr %t1 + store ptr %arg_ty, ptr %t2 + %t3 = load i32, ptr @g_nloc + %t4 = load ptr, ptr @g_loc_name + %t5 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 1 + %t6 = load i32, ptr %t5 + %t7 = icmp slt i32 %t3, %t6 + %t8 = zext i1 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then0, label %else1 +then0: + %t10 = load ptr, ptr @g_loc_name + %t11 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 0 + %t12 = load ptr, ptr %t11 + %t13 = load i32, ptr @g_nloc + %t14 = getelementptr inbounds ptr, ptr %t12, i32 %t13 + %t15 = load ptr, ptr %t0 + store ptr %t15, ptr %t14 + %t16 = load ptr, ptr @g_loc_reg + %t17 = getelementptr inbounds %LSlice, ptr %t16, i32 0, i32 0 + %t18 = load ptr, ptr %t17 + %t19 = load i32, ptr @g_nloc + %t20 = getelementptr inbounds ptr, ptr %t18, i32 %t19 + %t21 = load ptr, ptr %t1 + store ptr %t21, ptr %t20 + %t22 = load ptr, ptr @g_loc_ty + %t23 = getelementptr inbounds %LSlice, ptr %t22, i32 0, i32 0 + %t24 = load ptr, ptr %t23 + %t25 = load i32, ptr @g_nloc + %t26 = getelementptr inbounds ptr, ptr %t24, i32 %t25 + %t27 = load ptr, ptr %t2 + store ptr %t27, ptr %t26 + br label %ifend2 +else1: + %t28 = load ptr, ptr @g_loc_name + %t29 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 1 + %t30 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 2 + %t31 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 0 + %t32 = load i32, ptr %t29 + %t33 = load i32, ptr %t30 + %t34 = icmp sge i32 %t32, %t33 + br i1 %t34, label %grow3, label %put4 +grow3: + %t35 = mul i32 %t33, 2 + %t36 = icmp eq i32 %t33, 0 + %t37 = select i1 %t36, i32 8, i32 %t35 + %t38 = getelementptr ptr, ptr null, i32 1 + %t39 = ptrtoint ptr %t38 to i64 + %t40 = zext i32 %t37 to i64 + %t41 = mul i64 %t40, %t39 + %t42 = load ptr, ptr %t31 + %t43 = call ptr @realloc(ptr %t42, i64 %t41) + store ptr %t43, ptr %t31 + store i32 %t37, ptr %t30 + br label %put4 +put4: + %t44 = load ptr, ptr %t0 + %t45 = load ptr, ptr %t31 + %t46 = getelementptr inbounds ptr, ptr %t45, i32 %t32 + store ptr %t44, ptr %t46 + %t47 = add i32 %t32, 1 + store i32 %t47, ptr %t29 + %t48 = load ptr, ptr @g_loc_reg + %t49 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 1 + %t50 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 2 + %t51 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 0 + %t52 = load i32, ptr %t49 + %t53 = load i32, ptr %t50 + %t54 = icmp sge i32 %t52, %t53 + br i1 %t54, label %grow5, label %put6 +grow5: + %t55 = mul i32 %t53, 2 + %t56 = icmp eq i32 %t53, 0 + %t57 = select i1 %t56, i32 8, i32 %t55 + %t58 = getelementptr ptr, ptr null, i32 1 + %t59 = ptrtoint ptr %t58 to i64 + %t60 = zext i32 %t57 to i64 + %t61 = mul i64 %t60, %t59 + %t62 = load ptr, ptr %t51 + %t63 = call ptr @realloc(ptr %t62, i64 %t61) + store ptr %t63, ptr %t51 + store i32 %t57, ptr %t50 + br label %put6 +put6: + %t64 = load ptr, ptr %t1 + %t65 = load ptr, ptr %t51 + %t66 = getelementptr inbounds ptr, ptr %t65, i32 %t52 + store ptr %t64, ptr %t66 + %t67 = add i32 %t52, 1 + store i32 %t67, ptr %t49 + %t68 = load ptr, ptr @g_loc_ty + %t69 = getelementptr inbounds %LSlice, ptr %t68, i32 0, i32 1 + %t70 = getelementptr inbounds %LSlice, ptr %t68, i32 0, i32 2 + %t71 = getelementptr inbounds %LSlice, ptr %t68, i32 0, i32 0 + %t72 = load i32, ptr %t69 + %t73 = load i32, ptr %t70 + %t74 = icmp sge i32 %t72, %t73 + br i1 %t74, label %grow7, label %put8 +grow7: + %t75 = mul i32 %t73, 2 + %t76 = icmp eq i32 %t73, 0 + %t77 = select i1 %t76, i32 8, i32 %t75 + %t78 = getelementptr ptr, ptr null, i32 1 + %t79 = ptrtoint ptr %t78 to i64 + %t80 = zext i32 %t77 to i64 + %t81 = mul i64 %t80, %t79 + %t82 = load ptr, ptr %t71 + %t83 = call ptr @realloc(ptr %t82, i64 %t81) + store ptr %t83, ptr %t71 + store i32 %t77, ptr %t70 + br label %put8 +put8: + %t84 = load ptr, ptr %t2 + %t85 = load ptr, ptr %t71 + %t86 = getelementptr inbounds ptr, ptr %t85, i32 %t72 + store ptr %t84, ptr %t86 + %t87 = add i32 %t72, 1 + store i32 %t87, ptr %t69 + br label %ifend2 +ifend2: + %t88 = load i32, ptr @g_nloc + %t89 = add i32 %t88, 1 + store i32 %t89, ptr @g_nloc + br label %ret +ret: + ret void +} + +define i32 @fn_loc_find(ptr %arg_name) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t3 = alloca i32 + store ptr %arg_name, ptr %t0 + %t1 = load i32, ptr @g_nloc + %t2 = sub i32 %t1, 1 + store i32 %t2, ptr %t3 + br label %wcond0 +wcond0: + %t4 = load i32, ptr %t3 + %t5 = icmp sge i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + %t8 = load ptr, ptr @g_loc_name + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t9 + %t11 = load i32, ptr %t3 + %t12 = getelementptr inbounds ptr, ptr %t10, i32 %t11 + %t13 = load ptr, ptr %t12 + %t14 = load ptr, ptr %t0 + %t15 = call i32 @fn_streq(ptr %t13, ptr %t14) + %t16 = icmp ne i32 %t15, 0 + br i1 %t16, label %then3, label %ifend5 +then3: + %t17 = load i32, ptr %t3 + store i32 %t17, ptr %retval + br label %ret +ifend5: + %t18 = load i32, ptr %t3 + %t19 = sub i32 %t18, 1 + store i32 %t19, ptr %t3 + br label %wcond0 +wend2: + %t20 = sub i32 0, 1 + store i32 %t20, ptr %retval + br label %ret +ret: + %t21 = load i32, ptr %retval + ret i32 %t21 +} + +define i32 @fn_hexdig(i32 %arg_n) { +entry: + %retval = alloca i32 + %t0 = alloca i32 + store i32 %arg_n, ptr %t0 + %t1 = load i32, ptr %t0 + %t2 = icmp slt i32 %t1, 10 + %t3 = zext i1 %t2 to i32 + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + %t5 = load i32, ptr %t0 + %t6 = add i32 48, %t5 + store i32 %t6, ptr %retval + br label %ret +ifend2: + %t7 = load i32, ptr %t0 + %t8 = add i32 55, %t7 + store i32 %t8, ptr %retval + br label %ret +ret: + %t9 = load i32, ptr %retval + ret i32 %t9 +} + +define ptr @fn_emit_str_const(ptr %arg_s) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t4 = alloca ptr + %t9 = alloca i32 + %t14 = alloca i32 + %t25 = alloca i32 + %t26 = alloca i32 + %t27 = alloca i32 + %t28 = alloca i32 + store ptr %arg_s, ptr %t0 + %t1 = load i32, ptr @g_ll_str + %t2 = call ptr @fn_itoa(i32 %t1) + %t3 = call ptr @fn_sconcat(ptr @.str203, ptr %t2) + store ptr %t3, ptr %t4 + %t5 = load i32, ptr @g_ll_str + %t6 = add i32 %t5, 1 + store i32 %t6, ptr @g_ll_str + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_slen(ptr %t7) + store i32 %t8, ptr %t9 + %t10 = load ptr, ptr %t4 + call void @fn_emith(ptr %t10) + call void @fn_emith(ptr @.str204) + %t11 = load i32, ptr %t9 + %t12 = add i32 %t11, 1 + %t13 = call ptr @fn_itoa(i32 %t12) + call void @fn_emith(ptr %t13) + call void @fn_emith(ptr @.str205) + store i32 0, ptr %t14 + br label %wcond0 +wcond0: + %t15 = load i32, ptr %t14 + %t16 = load i32, ptr %t9 + %t17 = icmp slt i32 %t15, %t16 + %t18 = zext i1 %t17 to i32 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %wbody1, label %wend2 +wbody1: + %t20 = load ptr, ptr %t0 + %t21 = load i32, ptr %t14 + %t22 = getelementptr inbounds i8, ptr %t20, i32 %t21 + %t23 = load i8, ptr %t22 + %t24 = zext i8 %t23 to i32 + store i32 %t24, ptr %t25 + %t29 = load i32, ptr %t25 + %t30 = icmp eq i32 %t29, 34 + %t31 = zext i1 %t30 to i32 + %t32 = icmp ne i32 %t31, 0 + %t33 = zext i1 %t32 to i32 + store i32 %t33, ptr %t28 + br i1 %t32, label %scend4, label %sc3 +sc3: + %t34 = load i32, ptr %t25 + %t35 = icmp eq i32 %t34, 92 + %t36 = zext i1 %t35 to i32 + %t37 = icmp ne i32 %t36, 0 + %t38 = zext i1 %t37 to i32 + store i32 %t38, ptr %t28 + br label %scend4 +scend4: + %t39 = load i32, ptr %t28 + %t40 = icmp ne i32 %t39, 0 + %t41 = zext i1 %t40 to i32 + store i32 %t41, ptr %t27 + br i1 %t40, label %scend6, label %sc5 +sc5: + %t42 = load i32, ptr %t25 + %t43 = icmp slt i32 %t42, 32 + %t44 = zext i1 %t43 to i32 + %t45 = icmp ne i32 %t44, 0 + %t46 = zext i1 %t45 to i32 + store i32 %t46, ptr %t27 + br label %scend6 +scend6: + %t47 = load i32, ptr %t27 + %t48 = icmp ne i32 %t47, 0 + %t49 = zext i1 %t48 to i32 + store i32 %t49, ptr %t26 + br i1 %t48, label %scend8, label %sc7 +sc7: + %t50 = load i32, ptr %t25 + %t51 = icmp sgt i32 %t50, 126 + %t52 = zext i1 %t51 to i32 + %t53 = icmp ne i32 %t52, 0 + %t54 = zext i1 %t53 to i32 + store i32 %t54, ptr %t26 + br label %scend8 +scend8: + %t55 = load i32, ptr %t26 + %t56 = icmp ne i32 %t55, 0 + br i1 %t56, label %then9, label %else10 +then9: + %t57 = load ptr, ptr @g_head + call void @fn_buf_putc(ptr %t57, i32 92) + %t58 = load ptr, ptr @g_head + %t59 = load i32, ptr %t25 + %t60 = sdiv i32 %t59, 16 + %t61 = call i32 @fn_hexdig(i32 %t60) + call void @fn_buf_putc(ptr %t58, i32 %t61) + %t62 = load ptr, ptr @g_head + %t63 = load i32, ptr %t25 + %t64 = srem i32 %t63, 16 + %t65 = call i32 @fn_hexdig(i32 %t64) + call void @fn_buf_putc(ptr %t62, i32 %t65) + br label %ifend11 +else10: + %t66 = load ptr, ptr @g_head + %t67 = load i32, ptr %t25 + call void @fn_buf_putc(ptr %t66, i32 %t67) + br label %ifend11 +ifend11: + %t68 = load i32, ptr %t14 + %t69 = add i32 %t68, 1 + store i32 %t69, ptr %t14 + br label %wcond0 +wend2: + call void @fn_emith(ptr @.str206) + %t70 = load ptr, ptr %t4 + store ptr %t70, ptr %retval + br label %ret +ret: + %t71 = load ptr, ptr %retval + ret ptr %t71 +} + +define ptr @fn_emit_gep_i8(ptr %arg_base, ptr %arg_idx) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t3 = alloca ptr + store ptr %arg_base, ptr %t0 + store ptr %arg_idx, ptr %t1 + %t2 = call ptr @fn_nreg() + store ptr %t2, ptr %t3 + call void @fn_emit(ptr @.str207) + %t4 = load ptr, ptr %t3 + call void @fn_emit(ptr %t4) + call void @fn_emit(ptr @.str208) + %t5 = load ptr, ptr %t0 + call void @fn_emit(ptr %t5) + call void @fn_emit(ptr @.str209) + %t6 = load ptr, ptr %t1 + call void @fn_emit(ptr %t6) + call void @fn_emit(ptr @.str210) + %t7 = load ptr, ptr %t3 + store ptr %t7, ptr %retval + br label %ret +ret: + %t8 = load ptr, ptr %retval + ret ptr %t8 +} + +define ptr @fn_global_init(ptr %arg_d) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t16 = alloca ptr + %t17 = alloca i32 + %t18 = alloca i32 + %t49 = alloca i32 + %t50 = alloca i32 + store ptr %arg_d, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = icmp eq ptr %t3, null + %t5 = zext i1 %t4 to i32 + %t6 = icmp ne i32 %t5, 0 + br i1 %t6, label %then0, label %ifend2 +then0: + %t7 = load ptr, ptr %t0 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 3 + %t9 = load ptr, ptr %t8 + %t10 = call ptr @fn_llty(ptr %t9) + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str211) + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then3, label %ifend5 +then3: + store ptr @.str212, ptr %retval + br label %ret +ifend5: + store ptr @.str213, ptr %retval + br label %ret +ifend2: + %t13 = load ptr, ptr %t0 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 4 + %t15 = load ptr, ptr %t14 + store ptr %t15, ptr %t16 + %t19 = load ptr, ptr %t16 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 0 + %t21 = load i32, ptr %t20 + %t22 = icmp eq i32 %t21, 30 + %t23 = zext i1 %t22 to i32 + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t18 + br i1 %t24, label %scend7, label %sc6 +sc6: + %t26 = load ptr, ptr %t16 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 0 + %t28 = load i32, ptr %t27 + %t29 = icmp eq i32 %t28, 40 + %t30 = zext i1 %t29 to i32 + %t31 = icmp ne i32 %t30, 0 + %t32 = zext i1 %t31 to i32 + store i32 %t32, ptr %t18 + br label %scend7 +scend7: + %t33 = load i32, ptr %t18 + %t34 = icmp ne i32 %t33, 0 + %t35 = zext i1 %t34 to i32 + store i32 %t35, ptr %t17 + br i1 %t34, label %scend9, label %sc8 +sc8: + %t36 = load ptr, ptr %t16 + %t37 = getelementptr inbounds %Str_Node, ptr %t36, i32 0, i32 0 + %t38 = load i32, ptr %t37 + %t39 = icmp eq i32 %t38, 32 + %t40 = zext i1 %t39 to i32 + %t41 = icmp ne i32 %t40, 0 + %t42 = zext i1 %t41 to i32 + store i32 %t42, ptr %t17 + br label %scend9 +scend9: + %t43 = load i32, ptr %t17 + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then10, label %ifend12 +then10: + %t45 = load ptr, ptr %t16 + %t46 = getelementptr inbounds %Str_Node, ptr %t45, i32 0, i32 2 + %t47 = load i32, ptr %t46 + %t48 = call ptr @fn_itoa(i32 %t47) + store ptr %t48, ptr %retval + br label %ret +ifend12: + %t51 = load ptr, ptr %t16 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 0 + %t53 = load i32, ptr %t52 + %t54 = icmp eq i32 %t53, 38 + %t55 = zext i1 %t54 to i32 + %t56 = icmp ne i32 %t55, 0 + %t57 = zext i1 %t56 to i32 + store i32 %t57, ptr %t50 + br i1 %t56, label %sc13, label %scend14 +sc13: + %t58 = load ptr, ptr %t16 + %t59 = getelementptr inbounds %Str_Node, ptr %t58, i32 0, i32 1 + %t60 = load ptr, ptr %t59 + %t61 = call i32 @fn_streq(ptr %t60, ptr @.str214) + %t62 = icmp ne i32 %t61, 0 + %t63 = zext i1 %t62 to i32 + store i32 %t63, ptr %t50 + br label %scend14 +scend14: + %t64 = load i32, ptr %t50 + %t65 = icmp ne i32 %t64, 0 + %t66 = zext i1 %t65 to i32 + store i32 %t66, ptr %t49 + br i1 %t65, label %sc15, label %scend16 +sc15: + %t67 = load ptr, ptr %t16 + %t68 = getelementptr inbounds %Str_Node, ptr %t67, i32 0, i32 4 + %t69 = load ptr, ptr %t68 + %t70 = getelementptr inbounds %Str_Node, ptr %t69, i32 0, i32 0 + %t71 = load i32, ptr %t70 + %t72 = icmp eq i32 %t71, 30 + %t73 = zext i1 %t72 to i32 + %t74 = icmp ne i32 %t73, 0 + %t75 = zext i1 %t74 to i32 + store i32 %t75, ptr %t49 + br label %scend16 +scend16: + %t76 = load i32, ptr %t49 + %t77 = icmp ne i32 %t76, 0 + br i1 %t77, label %then17, label %ifend19 +then17: + %t78 = load ptr, ptr %t16 + %t79 = getelementptr inbounds %Str_Node, ptr %t78, i32 0, i32 4 + %t80 = load ptr, ptr %t79 + %t81 = getelementptr inbounds %Str_Node, ptr %t80, i32 0, i32 2 + %t82 = load i32, ptr %t81 + %t83 = call ptr @fn_itoa(i32 %t82) + %t84 = call ptr @fn_sconcat(ptr @.str215, ptr %t83) + store ptr %t84, ptr %retval + br label %ret +ifend19: + %t85 = load ptr, ptr %t0 + %t86 = getelementptr inbounds %Str_Node, ptr %t85, i32 0, i32 3 + %t87 = load ptr, ptr %t86 + %t88 = call ptr @fn_llty(ptr %t87) + %t89 = call i32 @fn_streq(ptr %t88, ptr @.str216) + %t90 = icmp ne i32 %t89, 0 + br i1 %t90, label %then20, label %ifend22 +then20: + store ptr @.str217, ptr %retval + br label %ret +ifend22: + store ptr @.str218, ptr %retval + br label %ret +ret: + %t91 = load ptr, ptr %retval + ret ptr %t91 +} + +define void @fn_emit_header() { +entry: + %t5 = alloca i32 + %t19 = alloca ptr + %t37 = alloca i32 + %t79 = alloca ptr + call void @fn_emith(ptr @.str219) + call void @fn_emith(ptr @.str220) + call void @fn_emith(ptr @.str221) + call void @fn_emith(ptr @.str222) + call void @fn_emith(ptr @.str223) + call void @fn_emith(ptr @.str224) + call void @fn_emith(ptr @.str225) + call void @fn_emith(ptr @.str226) + call void @fn_emith(ptr @.str227) + call void @fn_emith(ptr @.str228) + call void @fn_emith(ptr @.str229) + call void @fn_emith(ptr @.str230) + call void @fn_emith(ptr @.str231) + call void @fn_emith(ptr @.str232) + call void @fn_emith(ptr @.str233) + call void @fn_emith(ptr @.str234) + call void @fn_emith(ptr @.str235) + call void @fn_emith(ptr @.str236) + call void @fn_emith(ptr @.str237) + call void @fn_emith(ptr @.str238) + call void @fn_emith(ptr @.str239) + call void @fn_emith(ptr @.str240) + call void @fn_emith(ptr @.str241) + call void @fn_emith(ptr @.str242) + call void @fn_emith(ptr @.str243) + call void @fn_emith(ptr @.str244) + call void @fn_emith(ptr @.str245) + call void @fn_emith(ptr @.str246) + call void @fn_emith(ptr @.str247) + call void @fn_emith(ptr @.str248) + call void @fn_emith(ptr @.str249) + %t0 = load ptr, ptr @g_g_game_name + %t1 = call i32 @fn_slen(ptr %t0) + %t2 = add i32 %t1, 1 + %t3 = call ptr @fn_itoa(i32 %t2) + call void @fn_emith(ptr %t3) + call void @fn_emith(ptr @.str250) + %t4 = load ptr, ptr @g_g_game_name + call void @fn_emith(ptr %t4) + call void @fn_emith(ptr @.str251) + call void @fn_emith(ptr @.str252) + store i32 0, ptr %t5 + br label %wcond0 +wcond0: + %t6 = load i32, ptr %t5 + %t7 = load ptr, ptr @g_prog + %t8 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 1 + %t9 = load i32, ptr %t8 + %t10 = icmp slt i32 %t6, %t9 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %wbody1, label %wend2 +wbody1: + %t13 = load ptr, ptr @g_prog + %t14 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 0 + %t15 = load ptr, ptr %t14 + %t16 = load i32, ptr %t5 + %t17 = getelementptr inbounds ptr, ptr %t15, i32 %t16 + %t18 = load ptr, ptr %t17 + store ptr %t18, ptr %t19 + %t20 = load ptr, ptr %t19 + %t21 = getelementptr inbounds %Str_Node, ptr %t20, i32 0, i32 0 + %t22 = load i32, ptr %t21 + %t23 = icmp eq i32 %t22, 0 + %t24 = zext i1 %t23 to i32 + %t25 = icmp ne i32 %t24, 0 + br i1 %t25, label %then3, label %ifend5 +then3: + call void @fn_emith(ptr @.str253) + %t26 = load ptr, ptr %t19 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 1 + %t28 = load ptr, ptr %t27 + call void @fn_emith(ptr %t28) + call void @fn_emith(ptr @.str254) + %t29 = load ptr, ptr %t19 + %t30 = getelementptr inbounds %Str_Node, ptr %t29, i32 0, i32 7 + %t31 = load ptr, ptr %t30 + %t32 = getelementptr inbounds %LSlice, ptr %t31, i32 0, i32 1 + %t33 = load i32, ptr %t32 + %t34 = icmp eq i32 %t33, 0 + %t35 = zext i1 %t34 to i32 + %t36 = icmp ne i32 %t35, 0 + br i1 %t36, label %then6, label %ifend8 +then6: + call void @fn_emith(ptr @.str255) + br label %ifend8 +ifend8: + store i32 0, ptr %t37 + br label %wcond9 +wcond9: + %t38 = load i32, ptr %t37 + %t39 = load ptr, ptr %t19 + %t40 = getelementptr inbounds %Str_Node, ptr %t39, i32 0, i32 7 + %t41 = load ptr, ptr %t40 + %t42 = getelementptr inbounds %LSlice, ptr %t41, i32 0, i32 1 + %t43 = load i32, ptr %t42 + %t44 = icmp slt i32 %t38, %t43 + %t45 = zext i1 %t44 to i32 + %t46 = icmp ne i32 %t45, 0 + br i1 %t46, label %wbody10, label %wend11 +wbody10: + %t47 = load i32, ptr %t37 + %t48 = icmp sgt i32 %t47, 0 + %t49 = zext i1 %t48 to i32 + %t50 = icmp ne i32 %t49, 0 + br i1 %t50, label %then12, label %ifend14 +then12: + call void @fn_emith(ptr @.str256) + br label %ifend14 +ifend14: + %t51 = load ptr, ptr %t19 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 7 + %t53 = load ptr, ptr %t52 + %t54 = getelementptr inbounds %LSlice, ptr %t53, i32 0, i32 0 + %t55 = load ptr, ptr %t54 + %t56 = load i32, ptr %t37 + %t57 = getelementptr inbounds ptr, ptr %t55, i32 %t56 + %t58 = load ptr, ptr %t57 + %t59 = getelementptr inbounds %Str_Node, ptr %t58, i32 0, i32 3 + %t60 = load ptr, ptr %t59 + %t61 = call ptr @fn_llty(ptr %t60) + call void @fn_emith(ptr %t61) + %t62 = load i32, ptr %t37 + %t63 = add i32 %t62, 1 + store i32 %t63, ptr %t37 + br label %wcond9 +wend11: + call void @fn_emith(ptr @.str257) + br label %ifend5 +ifend5: + %t64 = load i32, ptr %t5 + %t65 = add i32 %t64, 1 + store i32 %t65, ptr %t5 + br label %wcond0 +wend2: + store i32 0, ptr %t5 + br label %wcond15 +wcond15: + %t66 = load i32, ptr %t5 + %t67 = load ptr, ptr @g_prog + %t68 = getelementptr inbounds %LSlice, ptr %t67, i32 0, i32 1 + %t69 = load i32, ptr %t68 + %t70 = icmp slt i32 %t66, %t69 + %t71 = zext i1 %t70 to i32 + %t72 = icmp ne i32 %t71, 0 + br i1 %t72, label %wbody16, label %wend17 +wbody16: + %t73 = load ptr, ptr @g_prog + %t74 = getelementptr inbounds %LSlice, ptr %t73, i32 0, i32 0 + %t75 = load ptr, ptr %t74 + %t76 = load i32, ptr %t5 + %t77 = getelementptr inbounds ptr, ptr %t75, i32 %t76 + %t78 = load ptr, ptr %t77 + store ptr %t78, ptr %t79 + %t80 = load ptr, ptr %t79 + %t81 = getelementptr inbounds %Str_Node, ptr %t80, i32 0, i32 0 + %t82 = load i32, ptr %t81 + %t83 = icmp eq i32 %t82, 2 + %t84 = zext i1 %t83 to i32 + %t85 = icmp ne i32 %t84, 0 + br i1 %t85, label %then18, label %ifend20 +then18: + call void @fn_emith(ptr @.str258) + %t86 = load ptr, ptr %t79 + %t87 = getelementptr inbounds %Str_Node, ptr %t86, i32 0, i32 1 + %t88 = load ptr, ptr %t87 + call void @fn_emith(ptr %t88) + call void @fn_emith(ptr @.str259) + %t89 = load ptr, ptr %t79 + %t90 = getelementptr inbounds %Str_Node, ptr %t89, i32 0, i32 3 + %t91 = load ptr, ptr %t90 + %t92 = call ptr @fn_llty(ptr %t91) + call void @fn_emith(ptr %t92) + call void @fn_emith(ptr @.str260) + %t93 = load ptr, ptr %t79 + %t94 = call ptr @fn_global_init(ptr %t93) + call void @fn_emith(ptr %t94) + call void @fn_emith(ptr @.str261) + br label %ifend20 +ifend20: + %t95 = load i32, ptr %t5 + %t96 = add i32 %t95, 1 + store i32 %t96, ptr %t5 + br label %wcond15 +wend17: + br label %ret +ret: + ret void +} + +define ptr @fn_emit_member_addr(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t5 = alloca ptr + %t10 = alloca ptr + %t24 = alloca i32 + %t39 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_emit_expr(ptr %t3) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Val, ptr %t6, i32 0, i32 1 + %t8 = load ptr, ptr %t7 + %t9 = call ptr @fn_layout_node(ptr %t8) + store ptr %t9, ptr %t10 + %t11 = load ptr, ptr %t10 + %t12 = icmp eq ptr %t11, null + %t13 = zext i1 %t12 to i32 + %t14 = icmp ne i32 %t13, 0 + br i1 %t14, label %then0, label %ifend2 +then0: + %t15 = load ptr, ptr %t5 + %t16 = getelementptr inbounds %Str_Val, ptr %t15, i32 0, i32 1 + %t17 = load ptr, ptr %t16 + %t18 = call ptr @fn_sconcat(ptr @.str262, ptr %t17) + call void @fn_perr(ptr %t18) + br label %ifend2 +ifend2: + %t19 = load ptr, ptr %t10 + %t20 = load ptr, ptr %t0 + %t21 = getelementptr inbounds %Str_Node, ptr %t20, i32 0, i32 1 + %t22 = load ptr, ptr %t21 + %t23 = call i32 @fn_field_index(ptr %t19, ptr %t22) + store i32 %t23, ptr %t24 + %t25 = load i32, ptr %t24 + %t26 = icmp slt i32 %t25, 0 + %t27 = zext i1 %t26 to i32 + %t28 = icmp ne i32 %t27, 0 + br i1 %t28, label %then3, label %ifend5 +then3: + %t29 = load ptr, ptr %t0 + %t30 = getelementptr inbounds %Str_Node, ptr %t29, i32 0, i32 1 + %t31 = load ptr, ptr %t30 + %t32 = call ptr @fn_sconcat(ptr @.str263, ptr %t31) + call void @fn_perr(ptr %t32) + br label %ifend5 +ifend5: + %t33 = load ptr, ptr %t10 + %t34 = load ptr, ptr %t0 + %t35 = getelementptr inbounds %Str_Node, ptr %t34, i32 0, i32 1 + %t36 = load ptr, ptr %t35 + %t37 = call ptr @fn_field_type(ptr %t33, ptr %t36) + store ptr %t37, ptr @g_g_addr_ty + %t38 = call ptr @fn_nreg() + store ptr %t38, ptr %t39 + call void @fn_emit(ptr @.str264) + %t40 = load ptr, ptr %t39 + call void @fn_emit(ptr %t40) + call void @fn_emit(ptr @.str265) + %t41 = load ptr, ptr %t5 + %t42 = getelementptr inbounds %Str_Val, ptr %t41, i32 0, i32 1 + %t43 = load ptr, ptr %t42 + %t44 = call ptr @fn_layout_ty(ptr %t43) + call void @fn_emit(ptr %t44) + call void @fn_emit(ptr @.str266) + %t45 = load ptr, ptr %t5 + %t46 = getelementptr inbounds %Str_Val, ptr %t45, i32 0, i32 0 + %t47 = load ptr, ptr %t46 + call void @fn_emit(ptr %t47) + call void @fn_emit(ptr @.str267) + %t48 = load i32, ptr %t24 + %t49 = call ptr @fn_itoa(i32 %t48) + call void @fn_emit(ptr %t49) + call void @fn_emit(ptr @.str268) + %t50 = load ptr, ptr %t39 + store ptr %t50, ptr %retval + br label %ret +ret: + %t51 = load ptr, ptr %retval + ret ptr %t51 +} + +define ptr @fn_emit_index_addr(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t5 = alloca ptr + %t17 = alloca ptr + %t20 = alloca ptr + %t26 = alloca ptr + %t33 = alloca ptr + %t35 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_emit_expr(ptr %t3) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Val, ptr %t6, i32 0, i32 1 + %t8 = load ptr, ptr %t7 + %t9 = call i32 @fn_is_slice_ty(ptr %t8) + %t10 = icmp eq i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %ifend2 +then0: + call void @fn_perr(ptr @.str269) + br label %ifend2 +ifend2: + %t13 = load ptr, ptr %t5 + %t14 = getelementptr inbounds %Str_Val, ptr %t13, i32 0, i32 1 + %t15 = load ptr, ptr %t14 + %t16 = call ptr @fn_slice_elem(ptr %t15) + store ptr %t16, ptr %t17 + %t18 = load ptr, ptr %t17 + store ptr %t18, ptr @g_g_addr_ty + %t19 = call ptr @fn_nreg() + store ptr %t19, ptr %t20 + call void @fn_emit(ptr @.str270) + %t21 = load ptr, ptr %t20 + call void @fn_emit(ptr %t21) + call void @fn_emit(ptr @.str271) + %t22 = load ptr, ptr %t5 + %t23 = getelementptr inbounds %Str_Val, ptr %t22, i32 0, i32 0 + %t24 = load ptr, ptr %t23 + call void @fn_emit(ptr %t24) + call void @fn_emit(ptr @.str272) + %t25 = call ptr @fn_nreg() + store ptr %t25, ptr %t26 + call void @fn_emit(ptr @.str273) + %t27 = load ptr, ptr %t26 + call void @fn_emit(ptr %t27) + call void @fn_emit(ptr @.str274) + %t28 = load ptr, ptr %t20 + call void @fn_emit(ptr %t28) + call void @fn_emit(ptr @.str275) + %t29 = load ptr, ptr %t0 + %t30 = getelementptr inbounds %Str_Node, ptr %t29, i32 0, i32 5 + %t31 = load ptr, ptr %t30 + %t32 = call ptr @fn_emit_expr(ptr %t31) + store ptr %t32, ptr %t33 + %t34 = call ptr @fn_nreg() + store ptr %t34, ptr %t35 + call void @fn_emit(ptr @.str276) + %t36 = load ptr, ptr %t35 + call void @fn_emit(ptr %t36) + call void @fn_emit(ptr @.str277) + %t37 = load ptr, ptr %t17 + %t38 = call ptr @fn_llty(ptr %t37) + call void @fn_emit(ptr %t38) + call void @fn_emit(ptr @.str278) + %t39 = load ptr, ptr %t26 + call void @fn_emit(ptr %t39) + call void @fn_emit(ptr @.str279) + %t40 = load ptr, ptr %t33 + %t41 = getelementptr inbounds %Str_Val, ptr %t40, i32 0, i32 0 + %t42 = load ptr, ptr %t41 + call void @fn_emit(ptr %t42) + call void @fn_emit(ptr @.str280) + %t43 = load ptr, ptr %t35 + store ptr %t43, ptr %retval + br label %ret +ret: + %t44 = load ptr, ptr %retval + ret ptr %t44 +} + +define i32 @fn_is_intrinsic(ptr %arg_name) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t20 = alloca i32 + %t21 = alloca i32 + %t39 = alloca i32 + %t40 = alloca i32 + %t58 = alloca i32 + %t59 = alloca i32 + %t77 = alloca i32 + %t88 = alloca i32 + %t89 = alloca i32 + %t90 = alloca i32 + %t115 = alloca i32 + %t126 = alloca i32 + %t127 = alloca i32 + %t128 = alloca i32 + %t129 = alloca i32 + %t130 = alloca i32 + %t169 = alloca i32 + store ptr %arg_name, ptr %t0 + %t3 = load ptr, ptr %t0 + %t4 = call i32 @fn_streq(ptr %t3, ptr @.str281) + %t5 = icmp ne i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %t2 + br i1 %t5, label %scend1, label %sc0 +sc0: + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str282) + %t9 = icmp ne i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + store i32 %t10, ptr %t2 + br label %scend1 +scend1: + %t11 = load i32, ptr %t2 + %t12 = icmp ne i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + store i32 %t13, ptr %t1 + br i1 %t12, label %scend3, label %sc2 +sc2: + %t14 = load ptr, ptr %t0 + %t15 = call i32 @fn_streq(ptr %t14, ptr @.str283) + %t16 = icmp ne i32 %t15, 0 + %t17 = zext i1 %t16 to i32 + store i32 %t17, ptr %t1 + br label %scend3 +scend3: + %t18 = load i32, ptr %t1 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then4, label %ifend6 +then4: + store i32 1, ptr %retval + br label %ret +ifend6: + %t22 = load ptr, ptr %t0 + %t23 = call i32 @fn_streq(ptr %t22, ptr @.str284) + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t21 + br i1 %t24, label %scend8, label %sc7 +sc7: + %t26 = load ptr, ptr %t0 + %t27 = call i32 @fn_streq(ptr %t26, ptr @.str285) + %t28 = icmp ne i32 %t27, 0 + %t29 = zext i1 %t28 to i32 + store i32 %t29, ptr %t21 + br label %scend8 +scend8: + %t30 = load i32, ptr %t21 + %t31 = icmp ne i32 %t30, 0 + %t32 = zext i1 %t31 to i32 + store i32 %t32, ptr %t20 + br i1 %t31, label %scend10, label %sc9 +sc9: + %t33 = load ptr, ptr %t0 + %t34 = call i32 @fn_streq(ptr %t33, ptr @.str286) + %t35 = icmp ne i32 %t34, 0 + %t36 = zext i1 %t35 to i32 + store i32 %t36, ptr %t20 + br label %scend10 +scend10: + %t37 = load i32, ptr %t20 + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %then11, label %ifend13 +then11: + store i32 1, ptr %retval + br label %ret +ifend13: + %t41 = load ptr, ptr %t0 + %t42 = call i32 @fn_streq(ptr %t41, ptr @.str287) + %t43 = icmp ne i32 %t42, 0 + %t44 = zext i1 %t43 to i32 + store i32 %t44, ptr %t40 + br i1 %t43, label %scend15, label %sc14 +sc14: + %t45 = load ptr, ptr %t0 + %t46 = call i32 @fn_streq(ptr %t45, ptr @.str288) + %t47 = icmp ne i32 %t46, 0 + %t48 = zext i1 %t47 to i32 + store i32 %t48, ptr %t40 + br label %scend15 +scend15: + %t49 = load i32, ptr %t40 + %t50 = icmp ne i32 %t49, 0 + %t51 = zext i1 %t50 to i32 + store i32 %t51, ptr %t39 + br i1 %t50, label %scend17, label %sc16 +sc16: + %t52 = load ptr, ptr %t0 + %t53 = call i32 @fn_streq(ptr %t52, ptr @.str289) + %t54 = icmp ne i32 %t53, 0 + %t55 = zext i1 %t54 to i32 + store i32 %t55, ptr %t39 + br label %scend17 +scend17: + %t56 = load i32, ptr %t39 + %t57 = icmp ne i32 %t56, 0 + br i1 %t57, label %then18, label %ifend20 +then18: + store i32 1, ptr %retval + br label %ret +ifend20: + %t60 = load ptr, ptr %t0 + %t61 = call i32 @fn_streq(ptr %t60, ptr @.str290) + %t62 = icmp ne i32 %t61, 0 + %t63 = zext i1 %t62 to i32 + store i32 %t63, ptr %t59 + br i1 %t62, label %scend22, label %sc21 +sc21: + %t64 = load ptr, ptr %t0 + %t65 = call i32 @fn_streq(ptr %t64, ptr @.str291) + %t66 = icmp ne i32 %t65, 0 + %t67 = zext i1 %t66 to i32 + store i32 %t67, ptr %t59 + br label %scend22 +scend22: + %t68 = load i32, ptr %t59 + %t69 = icmp ne i32 %t68, 0 + %t70 = zext i1 %t69 to i32 + store i32 %t70, ptr %t58 + br i1 %t69, label %scend24, label %sc23 +sc23: + %t71 = load ptr, ptr %t0 + %t72 = call i32 @fn_streq(ptr %t71, ptr @.str292) + %t73 = icmp ne i32 %t72, 0 + %t74 = zext i1 %t73 to i32 + store i32 %t74, ptr %t58 + br label %scend24 +scend24: + %t75 = load i32, ptr %t58 + %t76 = icmp ne i32 %t75, 0 + br i1 %t76, label %then25, label %ifend27 +then25: + store i32 1, ptr %retval + br label %ret +ifend27: + %t78 = load ptr, ptr %t0 + %t79 = call i32 @fn_streq(ptr %t78, ptr @.str293) + %t80 = icmp ne i32 %t79, 0 + %t81 = zext i1 %t80 to i32 + store i32 %t81, ptr %t77 + br i1 %t80, label %scend29, label %sc28 +sc28: + %t82 = load ptr, ptr %t0 + %t83 = call i32 @fn_streq(ptr %t82, ptr @.str294) + %t84 = icmp ne i32 %t83, 0 + %t85 = zext i1 %t84 to i32 + store i32 %t85, ptr %t77 + br label %scend29 +scend29: + %t86 = load i32, ptr %t77 + %t87 = icmp ne i32 %t86, 0 + br i1 %t87, label %then30, label %ifend32 +then30: + store i32 1, ptr %retval + br label %ret +ifend32: + %t91 = load ptr, ptr %t0 + %t92 = call i32 @fn_streq(ptr %t91, ptr @.str295) + %t93 = icmp ne i32 %t92, 0 + %t94 = zext i1 %t93 to i32 + store i32 %t94, ptr %t90 + br i1 %t93, label %scend34, label %sc33 +sc33: + %t95 = load ptr, ptr %t0 + %t96 = call i32 @fn_streq(ptr %t95, ptr @.str296) + %t97 = icmp ne i32 %t96, 0 + %t98 = zext i1 %t97 to i32 + store i32 %t98, ptr %t90 + br label %scend34 +scend34: + %t99 = load i32, ptr %t90 + %t100 = icmp ne i32 %t99, 0 + %t101 = zext i1 %t100 to i32 + store i32 %t101, ptr %t89 + br i1 %t100, label %scend36, label %sc35 +sc35: + %t102 = load ptr, ptr %t0 + %t103 = call i32 @fn_streq(ptr %t102, ptr @.str297) + %t104 = icmp ne i32 %t103, 0 + %t105 = zext i1 %t104 to i32 + store i32 %t105, ptr %t89 + br label %scend36 +scend36: + %t106 = load i32, ptr %t89 + %t107 = icmp ne i32 %t106, 0 + %t108 = zext i1 %t107 to i32 + store i32 %t108, ptr %t88 + br i1 %t107, label %scend38, label %sc37 +sc37: + %t109 = load ptr, ptr %t0 + %t110 = call i32 @fn_streq(ptr %t109, ptr @.str298) + %t111 = icmp ne i32 %t110, 0 + %t112 = zext i1 %t111 to i32 + store i32 %t112, ptr %t88 + br label %scend38 +scend38: + %t113 = load i32, ptr %t88 + %t114 = icmp ne i32 %t113, 0 + br i1 %t114, label %then39, label %ifend41 +then39: + store i32 1, ptr %retval + br label %ret +ifend41: + %t116 = load ptr, ptr %t0 + %t117 = call i32 @fn_streq(ptr %t116, ptr @.str299) + %t118 = icmp ne i32 %t117, 0 + %t119 = zext i1 %t118 to i32 + store i32 %t119, ptr %t115 + br i1 %t118, label %scend43, label %sc42 +sc42: + %t120 = load ptr, ptr %t0 + %t121 = call i32 @fn_streq(ptr %t120, ptr @.str300) + %t122 = icmp ne i32 %t121, 0 + %t123 = zext i1 %t122 to i32 + store i32 %t123, ptr %t115 + br label %scend43 +scend43: + %t124 = load i32, ptr %t115 + %t125 = icmp ne i32 %t124, 0 + br i1 %t125, label %then44, label %ifend46 +then44: + store i32 1, ptr %retval + br label %ret +ifend46: + %t131 = load ptr, ptr %t0 + %t132 = call i32 @fn_streq(ptr %t131, ptr @.str301) + %t133 = icmp ne i32 %t132, 0 + %t134 = zext i1 %t133 to i32 + store i32 %t134, ptr %t130 + br i1 %t133, label %scend48, label %sc47 +sc47: + %t135 = load ptr, ptr %t0 + %t136 = call i32 @fn_streq(ptr %t135, ptr @.str302) + %t137 = icmp ne i32 %t136, 0 + %t138 = zext i1 %t137 to i32 + store i32 %t138, ptr %t130 + br label %scend48 +scend48: + %t139 = load i32, ptr %t130 + %t140 = icmp ne i32 %t139, 0 + %t141 = zext i1 %t140 to i32 + store i32 %t141, ptr %t129 + br i1 %t140, label %scend50, label %sc49 +sc49: + %t142 = load ptr, ptr %t0 + %t143 = call i32 @fn_streq(ptr %t142, ptr @.str303) + %t144 = icmp ne i32 %t143, 0 + %t145 = zext i1 %t144 to i32 + store i32 %t145, ptr %t129 + br label %scend50 +scend50: + %t146 = load i32, ptr %t129 + %t147 = icmp ne i32 %t146, 0 + %t148 = zext i1 %t147 to i32 + store i32 %t148, ptr %t128 + br i1 %t147, label %scend52, label %sc51 +sc51: + %t149 = load ptr, ptr %t0 + %t150 = call i32 @fn_streq(ptr %t149, ptr @.str304) + %t151 = icmp ne i32 %t150, 0 + %t152 = zext i1 %t151 to i32 + store i32 %t152, ptr %t128 + br label %scend52 +scend52: + %t153 = load i32, ptr %t128 + %t154 = icmp ne i32 %t153, 0 + %t155 = zext i1 %t154 to i32 + store i32 %t155, ptr %t127 + br i1 %t154, label %scend54, label %sc53 +sc53: + %t156 = load ptr, ptr %t0 + %t157 = call i32 @fn_streq(ptr %t156, ptr @.str305) + %t158 = icmp ne i32 %t157, 0 + %t159 = zext i1 %t158 to i32 + store i32 %t159, ptr %t127 + br label %scend54 +scend54: + %t160 = load i32, ptr %t127 + %t161 = icmp ne i32 %t160, 0 + %t162 = zext i1 %t161 to i32 + store i32 %t162, ptr %t126 + br i1 %t161, label %scend56, label %sc55 +sc55: + %t163 = load ptr, ptr %t0 + %t164 = call i32 @fn_streq(ptr %t163, ptr @.str306) + %t165 = icmp ne i32 %t164, 0 + %t166 = zext i1 %t165 to i32 + store i32 %t166, ptr %t126 + br label %scend56 +scend56: + %t167 = load i32, ptr %t126 + %t168 = icmp ne i32 %t167, 0 + br i1 %t168, label %then57, label %ifend59 +then57: + store i32 1, ptr %retval + br label %ret +ifend59: + %t170 = load ptr, ptr %t0 + %t171 = call i32 @fn_streq(ptr %t170, ptr @.str307) + %t172 = icmp ne i32 %t171, 0 + %t173 = zext i1 %t172 to i32 + store i32 %t173, ptr %t169 + br i1 %t172, label %scend61, label %sc60 +sc60: + %t174 = load ptr, ptr %t0 + %t175 = call i32 @fn_streq(ptr %t174, ptr @.str308) + %t176 = icmp ne i32 %t175, 0 + %t177 = zext i1 %t176 to i32 + store i32 %t177, ptr %t169 + br label %scend61 +scend61: + %t178 = load i32, ptr %t169 + %t179 = icmp ne i32 %t178, 0 + br i1 %t179, label %then62, label %ifend64 +then62: + store i32 1, ptr %retval + br label %ret +ifend64: + store i32 0, ptr %retval + br label %ret +ret: + %t180 = load i32, ptr %retval + ret i32 %t180 +} + +define ptr @fn_emit_bind(ptr %arg_rest) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t2 = alloca ptr + store ptr %arg_rest, ptr %t0 + %t1 = call ptr @fn_nreg() + store ptr %t1, ptr %t2 + call void @fn_emit(ptr @.str309) + %t3 = load ptr, ptr %t2 + call void @fn_emit(ptr %t3) + call void @fn_emit(ptr @.str310) + %t4 = load ptr, ptr %t0 + call void @fn_emit(ptr %t4) + call void @fn_emit(ptr @.str311) + %t5 = load ptr, ptr %t2 + store ptr %t5, ptr %retval + br label %ret +ret: + %t6 = load ptr, ptr %retval + ret ptr %t6 +} + +define ptr @fn_arg_code(ptr %arg_e, i32 %arg_i) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t11 = alloca ptr + store ptr %arg_e, ptr %t0 + store i32 %arg_i, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = getelementptr inbounds %Str_Node, ptr %t2, i32 0, i32 7 + %t4 = load ptr, ptr %t3 + %t5 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 0 + %t6 = load ptr, ptr %t5 + %t7 = load i32, ptr %t1 + %t8 = getelementptr inbounds ptr, ptr %t6, i32 %t7 + %t9 = load ptr, ptr %t8 + %t10 = call ptr @fn_emit_expr(ptr %t9) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = getelementptr inbounds %Str_Val, ptr %t12, i32 0, i32 0 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %retval + br label %ret +ret: + %t15 = load ptr, ptr %retval + ret ptr %t15 +} + +define ptr @fn_emit_intrinsic(ptr %arg_name, ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t11 = alloca ptr + %t16 = alloca ptr + %t27 = alloca ptr + %t30 = alloca ptr + %t35 = alloca ptr + %t49 = alloca ptr + %t52 = alloca ptr + %t56 = alloca ptr + %t60 = alloca ptr + %t71 = alloca ptr + %t74 = alloca ptr + %t77 = alloca ptr + %t81 = alloca ptr + %t86 = alloca ptr + %t95 = alloca ptr + %t100 = alloca ptr + %t111 = alloca ptr + %t114 = alloca ptr + %t123 = alloca i32 + %t136 = alloca ptr + %t139 = alloca ptr + %t142 = alloca ptr + %t147 = alloca ptr + %t148 = alloca ptr + %t165 = alloca ptr + %t176 = alloca ptr + %t179 = alloca ptr + %t182 = alloca ptr + %t187 = alloca ptr + %t204 = alloca ptr + %t209 = alloca ptr + %t220 = alloca ptr + %t228 = alloca ptr + %t236 = alloca ptr + %t249 = alloca ptr + %t251 = alloca ptr + %t258 = alloca ptr + %t268 = alloca ptr + %t281 = alloca ptr + %t292 = alloca ptr + %t303 = alloca ptr + %t309 = alloca i32 + %t310 = alloca i32 + %t311 = alloca i32 + %t312 = alloca i32 + %t346 = alloca ptr + %t349 = alloca ptr + %t350 = alloca ptr + %t377 = alloca ptr + %t380 = alloca ptr + %t382 = alloca ptr + %t395 = alloca ptr + %t398 = alloca ptr + %t401 = alloca ptr + %t403 = alloca ptr + store ptr %arg_name, ptr %t0 + store ptr %arg_e, ptr %t1 + store i32 1, ptr @g_g_intrin_ok + %t2 = load ptr, ptr %t0 + %t3 = call i32 @fn_streq(ptr %t2, ptr @.str312) + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + %t5 = call ptr @fn_val(ptr @.str313, ptr @.str314) + store ptr %t5, ptr %retval + br label %ret +ifend2: + %t6 = load ptr, ptr %t0 + %t7 = call i32 @fn_streq(ptr %t6, ptr @.str315) + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %then3, label %ifend5 +then3: + %t9 = load ptr, ptr %t1 + %t10 = call ptr @fn_arg_code(ptr %t9, i32 0) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = call ptr @fn_sconcat(ptr %t12, ptr @.str317) + %t14 = call ptr @fn_sconcat(ptr @.str316, ptr %t13) + %t15 = call ptr @fn_emit_bind(ptr %t14) + store ptr %t15, ptr %t16 + %t17 = load ptr, ptr %t16 + %t18 = call ptr @fn_sconcat(ptr %t17, ptr @.str319) + %t19 = call ptr @fn_sconcat(ptr @.str318, ptr %t18) + %t20 = call ptr @fn_emit_bind(ptr %t19) + %t21 = call ptr @fn_val(ptr %t20, ptr @.str320) + store ptr %t21, ptr %retval + br label %ret +ifend5: + %t22 = load ptr, ptr %t0 + %t23 = call i32 @fn_streq(ptr %t22, ptr @.str321) + %t24 = icmp ne i32 %t23, 0 + br i1 %t24, label %then6, label %ifend8 +then6: + %t25 = load ptr, ptr %t1 + %t26 = call ptr @fn_arg_code(ptr %t25, i32 0) + store ptr %t26, ptr %t27 + %t28 = load ptr, ptr %t1 + %t29 = call ptr @fn_arg_code(ptr %t28, i32 1) + store ptr %t29, ptr %t30 + %t31 = load ptr, ptr %t30 + %t32 = call ptr @fn_sconcat(ptr %t31, ptr @.str323) + %t33 = call ptr @fn_sconcat(ptr @.str322, ptr %t32) + %t34 = call ptr @fn_emit_bind(ptr %t33) + store ptr %t34, ptr %t35 + %t36 = load ptr, ptr %t27 + %t37 = load ptr, ptr %t35 + %t38 = call ptr @fn_sconcat(ptr %t37, ptr @.str326) + %t39 = call ptr @fn_sconcat(ptr @.str325, ptr %t38) + %t40 = call ptr @fn_sconcat(ptr %t36, ptr %t39) + %t41 = call ptr @fn_sconcat(ptr @.str324, ptr %t40) + %t42 = call ptr @fn_emit_bind(ptr %t41) + %t43 = call ptr @fn_val(ptr %t42, ptr @.str327) + store ptr %t43, ptr %retval + br label %ret +ifend8: + %t44 = load ptr, ptr %t0 + %t45 = call i32 @fn_streq(ptr %t44, ptr @.str328) + %t46 = icmp ne i32 %t45, 0 + br i1 %t46, label %then9, label %ifend11 +then9: + %t47 = load ptr, ptr %t1 + %t48 = call ptr @fn_arg_code(ptr %t47, i32 0) + store ptr %t48, ptr %t49 + %t50 = load ptr, ptr %t1 + %t51 = call ptr @fn_arg_code(ptr %t50, i32 1) + store ptr %t51, ptr %t52 + %t53 = load ptr, ptr %t49 + %t54 = load ptr, ptr %t52 + %t55 = call ptr @fn_emit_gep_i8(ptr %t53, ptr %t54) + store ptr %t55, ptr %t56 + %t57 = load ptr, ptr %t56 + %t58 = call ptr @fn_sconcat(ptr @.str329, ptr %t57) + %t59 = call ptr @fn_emit_bind(ptr %t58) + store ptr %t59, ptr %t60 + %t61 = load ptr, ptr %t60 + %t62 = call ptr @fn_sconcat(ptr %t61, ptr @.str331) + %t63 = call ptr @fn_sconcat(ptr @.str330, ptr %t62) + %t64 = call ptr @fn_emit_bind(ptr %t63) + %t65 = call ptr @fn_val(ptr %t64, ptr @.str332) + store ptr %t65, ptr %retval + br label %ret +ifend11: + %t66 = load ptr, ptr %t0 + %t67 = call i32 @fn_streq(ptr %t66, ptr @.str333) + %t68 = icmp ne i32 %t67, 0 + br i1 %t68, label %then12, label %ifend14 +then12: + %t69 = load ptr, ptr %t1 + %t70 = call ptr @fn_arg_code(ptr %t69, i32 0) + store ptr %t70, ptr %t71 + %t72 = load ptr, ptr %t1 + %t73 = call ptr @fn_arg_code(ptr %t72, i32 1) + store ptr %t73, ptr %t74 + %t75 = load ptr, ptr %t1 + %t76 = call ptr @fn_arg_code(ptr %t75, i32 2) + store ptr %t76, ptr %t77 + %t78 = load ptr, ptr %t71 + %t79 = load ptr, ptr %t74 + %t80 = call ptr @fn_emit_gep_i8(ptr %t78, ptr %t79) + store ptr %t80, ptr %t81 + %t82 = load ptr, ptr %t77 + %t83 = call ptr @fn_sconcat(ptr %t82, ptr @.str335) + %t84 = call ptr @fn_sconcat(ptr @.str334, ptr %t83) + %t85 = call ptr @fn_emit_bind(ptr %t84) + store ptr %t85, ptr %t86 + call void @fn_emit(ptr @.str336) + %t87 = load ptr, ptr %t86 + call void @fn_emit(ptr %t87) + call void @fn_emit(ptr @.str337) + %t88 = load ptr, ptr %t81 + call void @fn_emit(ptr %t88) + call void @fn_emit(ptr @.str338) + %t89 = call ptr @fn_val(ptr @.str339, ptr @.str340) + store ptr %t89, ptr %retval + br label %ret +ifend14: + %t90 = load ptr, ptr %t0 + %t91 = call i32 @fn_streq(ptr %t90, ptr @.str341) + %t92 = icmp ne i32 %t91, 0 + br i1 %t92, label %then15, label %ifend17 +then15: + %t93 = load ptr, ptr %t1 + %t94 = call ptr @fn_arg_code(ptr %t93, i32 0) + store ptr %t94, ptr %t95 + %t96 = load ptr, ptr %t95 + %t97 = call ptr @fn_sconcat(ptr %t96, ptr @.str343) + %t98 = call ptr @fn_sconcat(ptr @.str342, ptr %t97) + %t99 = call ptr @fn_emit_bind(ptr %t98) + store ptr %t99, ptr %t100 + %t101 = load ptr, ptr %t100 + %t102 = call ptr @fn_sconcat(ptr %t101, ptr @.str345) + %t103 = call ptr @fn_sconcat(ptr @.str344, ptr %t102) + %t104 = call ptr @fn_emit_bind(ptr %t103) + %t105 = call ptr @fn_val(ptr %t104, ptr @.str346) + store ptr %t105, ptr %retval + br label %ret +ifend17: + %t106 = load ptr, ptr %t0 + %t107 = call i32 @fn_streq(ptr %t106, ptr @.str347) + %t108 = icmp ne i32 %t107, 0 + br i1 %t108, label %then18, label %ifend20 +then18: + %t109 = load ptr, ptr %t1 + %t110 = call ptr @fn_arg_code(ptr %t109, i32 0) + store ptr %t110, ptr %t111 + %t112 = load ptr, ptr %t1 + %t113 = call ptr @fn_arg_code(ptr %t112, i32 1) + store ptr %t113, ptr %t114 + %t115 = load ptr, ptr %t111 + %t116 = load ptr, ptr %t114 + %t117 = call ptr @fn_sconcat(ptr %t116, ptr @.str350) + %t118 = call ptr @fn_sconcat(ptr @.str349, ptr %t117) + %t119 = call ptr @fn_sconcat(ptr %t115, ptr %t118) + %t120 = call ptr @fn_sconcat(ptr @.str348, ptr %t119) + %t121 = call ptr @fn_emit_bind(ptr %t120) + %t122 = call ptr @fn_val(ptr %t121, ptr @.str351) + store ptr %t122, ptr %retval + br label %ret +ifend20: + %t124 = load ptr, ptr %t0 + %t125 = call i32 @fn_streq(ptr %t124, ptr @.str352) + %t126 = icmp ne i32 %t125, 0 + %t127 = zext i1 %t126 to i32 + store i32 %t127, ptr %t123 + br i1 %t126, label %scend22, label %sc21 +sc21: + %t128 = load ptr, ptr %t0 + %t129 = call i32 @fn_streq(ptr %t128, ptr @.str353) + %t130 = icmp ne i32 %t129, 0 + %t131 = zext i1 %t130 to i32 + store i32 %t131, ptr %t123 + br label %scend22 +scend22: + %t132 = load i32, ptr %t123 + %t133 = icmp ne i32 %t132, 0 + br i1 %t133, label %then23, label %ifend25 +then23: + %t134 = load ptr, ptr %t1 + %t135 = call ptr @fn_arg_code(ptr %t134, i32 0) + store ptr %t135, ptr %t136 + %t137 = load ptr, ptr %t1 + %t138 = call ptr @fn_arg_code(ptr %t137, i32 1) + store ptr %t138, ptr %t139 + %t140 = load ptr, ptr %t1 + %t141 = call ptr @fn_arg_code(ptr %t140, i32 2) + store ptr %t141, ptr %t142 + %t143 = load ptr, ptr %t142 + %t144 = call ptr @fn_sconcat(ptr %t143, ptr @.str355) + %t145 = call ptr @fn_sconcat(ptr @.str354, ptr %t144) + %t146 = call ptr @fn_emit_bind(ptr %t145) + store ptr %t146, ptr %t147 + store ptr @.str356, ptr %t148 + %t149 = load ptr, ptr %t0 + %t150 = call i32 @fn_streq(ptr %t149, ptr @.str357) + %t151 = icmp ne i32 %t150, 0 + br i1 %t151, label %then26, label %ifend28 +then26: + store ptr @.str358, ptr %t148 + br label %ifend28 +ifend28: + %t152 = load ptr, ptr %t148 + %t153 = load ptr, ptr %t139 + %t154 = load ptr, ptr %t147 + %t155 = load ptr, ptr %t136 + %t156 = call ptr @fn_sconcat(ptr %t155, ptr @.str363) + %t157 = call ptr @fn_sconcat(ptr @.str362, ptr %t156) + %t158 = call ptr @fn_sconcat(ptr %t154, ptr %t157) + %t159 = call ptr @fn_sconcat(ptr @.str361, ptr %t158) + %t160 = call ptr @fn_sconcat(ptr %t153, ptr %t159) + %t161 = call ptr @fn_sconcat(ptr @.str360, ptr %t160) + %t162 = call ptr @fn_sconcat(ptr %t152, ptr %t161) + %t163 = call ptr @fn_sconcat(ptr @.str359, ptr %t162) + %t164 = call ptr @fn_emit_bind(ptr %t163) + store ptr %t164, ptr %t165 + %t166 = load ptr, ptr %t165 + %t167 = call ptr @fn_sconcat(ptr %t166, ptr @.str365) + %t168 = call ptr @fn_sconcat(ptr @.str364, ptr %t167) + %t169 = call ptr @fn_emit_bind(ptr %t168) + %t170 = call ptr @fn_val(ptr %t169, ptr @.str366) + store ptr %t170, ptr %retval + br label %ret +ifend25: + %t171 = load ptr, ptr %t0 + %t172 = call i32 @fn_streq(ptr %t171, ptr @.str367) + %t173 = icmp ne i32 %t172, 0 + br i1 %t173, label %then29, label %ifend31 +then29: + %t174 = load ptr, ptr %t1 + %t175 = call ptr @fn_arg_code(ptr %t174, i32 0) + store ptr %t175, ptr %t176 + %t177 = load ptr, ptr %t1 + %t178 = call ptr @fn_arg_code(ptr %t177, i32 1) + store ptr %t178, ptr %t179 + %t180 = load ptr, ptr %t1 + %t181 = call ptr @fn_arg_code(ptr %t180, i32 2) + store ptr %t181, ptr %t182 + %t183 = load ptr, ptr %t179 + %t184 = call ptr @fn_sconcat(ptr %t183, ptr @.str369) + %t185 = call ptr @fn_sconcat(ptr @.str368, ptr %t184) + %t186 = call ptr @fn_emit_bind(ptr %t185) + store ptr %t186, ptr %t187 + %t188 = load ptr, ptr %t176 + %t189 = load ptr, ptr %t187 + %t190 = load ptr, ptr %t182 + %t191 = call ptr @fn_sconcat(ptr %t190, ptr @.str373) + %t192 = call ptr @fn_sconcat(ptr @.str372, ptr %t191) + %t193 = call ptr @fn_sconcat(ptr %t189, ptr %t192) + %t194 = call ptr @fn_sconcat(ptr @.str371, ptr %t193) + %t195 = call ptr @fn_sconcat(ptr %t188, ptr %t194) + %t196 = call ptr @fn_sconcat(ptr @.str370, ptr %t195) + %t197 = call ptr @fn_emit_bind(ptr %t196) + %t198 = call ptr @fn_val(ptr %t197, ptr @.str374) + store ptr %t198, ptr %retval + br label %ret +ifend31: + %t199 = load ptr, ptr %t0 + %t200 = call i32 @fn_streq(ptr %t199, ptr @.str375) + %t201 = icmp ne i32 %t200, 0 + br i1 %t201, label %then32, label %ifend34 +then32: + %t202 = load ptr, ptr %t1 + %t203 = call ptr @fn_arg_code(ptr %t202, i32 0) + store ptr %t203, ptr %t204 + %t205 = load ptr, ptr %t204 + %t206 = call ptr @fn_sconcat(ptr %t205, ptr @.str377) + %t207 = call ptr @fn_sconcat(ptr @.str376, ptr %t206) + %t208 = call ptr @fn_emit_bind(ptr %t207) + store ptr %t208, ptr %t209 + %t210 = load ptr, ptr %t209 + %t211 = call ptr @fn_sconcat(ptr %t210, ptr @.str379) + %t212 = call ptr @fn_sconcat(ptr @.str378, ptr %t211) + %t213 = call ptr @fn_emit_bind(ptr %t212) + %t214 = call ptr @fn_val(ptr %t213, ptr @.str380) + store ptr %t214, ptr %retval + br label %ret +ifend34: + %t215 = load ptr, ptr %t0 + %t216 = call i32 @fn_streq(ptr %t215, ptr @.str381) + %t217 = icmp ne i32 %t216, 0 + br i1 %t217, label %then35, label %ifend37 +then35: + %t218 = load ptr, ptr %t1 + %t219 = call ptr @fn_arg_code(ptr %t218, i32 0) + store ptr %t219, ptr %t220 + call void @fn_emit(ptr @.str382) + %t221 = load ptr, ptr %t220 + call void @fn_emit(ptr %t221) + call void @fn_emit(ptr @.str383) + %t222 = call ptr @fn_val(ptr @.str384, ptr @.str385) + store ptr %t222, ptr %retval + br label %ret +ifend37: + %t223 = load ptr, ptr %t0 + %t224 = call i32 @fn_streq(ptr %t223, ptr @.str386) + %t225 = icmp ne i32 %t224, 0 + br i1 %t225, label %then38, label %ifend40 +then38: + %t226 = load ptr, ptr %t1 + %t227 = call ptr @fn_arg_code(ptr %t226, i32 0) + store ptr %t227, ptr %t228 + call void @fn_emit(ptr @.str387) + %t229 = load ptr, ptr %t228 + call void @fn_emit(ptr %t229) + call void @fn_emit(ptr @.str388) + %t230 = call ptr @fn_val(ptr @.str389, ptr @.str390) + store ptr %t230, ptr %retval + br label %ret +ifend40: + %t231 = load ptr, ptr %t0 + %t232 = call i32 @fn_streq(ptr %t231, ptr @.str391) + %t233 = icmp ne i32 %t232, 0 + br i1 %t233, label %then41, label %ifend43 +then41: + %t234 = load ptr, ptr %t1 + %t235 = call ptr @fn_arg_code(ptr %t234, i32 0) + store ptr %t235, ptr %t236 + call void @fn_emit(ptr @.str392) + %t237 = load ptr, ptr %t236 + call void @fn_emit(ptr %t237) + call void @fn_emit(ptr @.str393) + %t238 = call ptr @fn_val(ptr @.str394, ptr @.str395) + store ptr %t238, ptr %retval + br label %ret +ifend43: + %t239 = load ptr, ptr %t0 + %t240 = call i32 @fn_streq(ptr %t239, ptr @.str396) + %t241 = icmp ne i32 %t240, 0 + br i1 %t241, label %then44, label %ifend46 +then44: + %t242 = call ptr @fn_emit_bind(ptr @.str397) + %t243 = call ptr @fn_val(ptr %t242, ptr @.str398) + store ptr %t243, ptr %retval + br label %ret +ifend46: + %t244 = load ptr, ptr %t0 + %t245 = call i32 @fn_streq(ptr %t244, ptr @.str399) + %t246 = icmp ne i32 %t245, 0 + br i1 %t246, label %then47, label %ifend49 +then47: + %t247 = load ptr, ptr %t1 + %t248 = call ptr @fn_arg_code(ptr %t247, i32 0) + store ptr %t248, ptr %t249 + %t250 = call ptr @fn_emit_bind(ptr @.str400) + store ptr %t250, ptr %t251 + %t252 = load ptr, ptr %t251 + %t253 = load ptr, ptr %t249 + %t254 = call ptr @fn_sconcat(ptr @.str402, ptr %t253) + %t255 = call ptr @fn_sconcat(ptr %t252, ptr %t254) + %t256 = call ptr @fn_sconcat(ptr @.str401, ptr %t255) + %t257 = call ptr @fn_emit_bind(ptr %t256) + store ptr %t257, ptr %t258 + %t259 = load ptr, ptr %t258 + %t260 = call ptr @fn_sconcat(ptr @.str403, ptr %t259) + %t261 = call ptr @fn_emit_bind(ptr %t260) + %t262 = call ptr @fn_val(ptr %t261, ptr @.str404) + store ptr %t262, ptr %retval + br label %ret +ifend49: + %t263 = load ptr, ptr %t0 + %t264 = call i32 @fn_streq(ptr %t263, ptr @.str405) + %t265 = icmp ne i32 %t264, 0 + br i1 %t265, label %then50, label %ifend52 +then50: + %t266 = load ptr, ptr %t1 + %t267 = call ptr @fn_arg_code(ptr %t266, i32 0) + store ptr %t267, ptr %t268 + call void @fn_emit(ptr @.str406) + %t269 = load ptr, ptr %t268 + call void @fn_emit(ptr %t269) + call void @fn_emit(ptr @.str407) + call void @fn_emit(ptr @.str408) + store i32 1, ptr @g_g_term + %t270 = call ptr @fn_val(ptr @.str409, ptr @.str410) + store ptr %t270, ptr %retval + br label %ret +ifend52: + %t271 = load ptr, ptr %t0 + %t272 = call i32 @fn_streq(ptr %t271, ptr @.str411) + %t273 = icmp ne i32 %t272, 0 + br i1 %t273, label %then53, label %ifend55 +then53: + %t274 = call ptr @fn_emit_bind(ptr @.str412) + %t275 = call ptr @fn_val(ptr %t274, ptr @.str413) + store ptr %t275, ptr %retval + br label %ret +ifend55: + %t276 = load ptr, ptr %t0 + %t277 = call i32 @fn_streq(ptr %t276, ptr @.str414) + %t278 = icmp ne i32 %t277, 0 + br i1 %t278, label %then56, label %ifend58 +then56: + %t279 = load ptr, ptr %t1 + %t280 = call ptr @fn_arg_code(ptr %t279, i32 0) + store ptr %t280, ptr %t281 + %t282 = load ptr, ptr %t281 + %t283 = call ptr @fn_sconcat(ptr %t282, ptr @.str416) + %t284 = call ptr @fn_sconcat(ptr @.str415, ptr %t283) + %t285 = call ptr @fn_emit_bind(ptr %t284) + %t286 = call ptr @fn_val(ptr %t285, ptr @.str417) + store ptr %t286, ptr %retval + br label %ret +ifend58: + %t287 = load ptr, ptr %t0 + %t288 = call i32 @fn_streq(ptr %t287, ptr @.str418) + %t289 = icmp ne i32 %t288, 0 + br i1 %t289, label %then59, label %ifend61 +then59: + %t290 = load ptr, ptr %t1 + %t291 = call ptr @fn_arg_code(ptr %t290, i32 0) + store ptr %t291, ptr %t292 + %t293 = load ptr, ptr %t292 + %t294 = call ptr @fn_sconcat(ptr %t293, ptr @.str420) + %t295 = call ptr @fn_sconcat(ptr @.str419, ptr %t294) + %t296 = call ptr @fn_emit_bind(ptr %t295) + %t297 = call ptr @fn_val(ptr %t296, ptr @.str421) + store ptr %t297, ptr %retval + br label %ret +ifend61: + %t298 = load ptr, ptr %t0 + %t299 = call i32 @fn_streq(ptr %t298, ptr @.str422) + %t300 = icmp ne i32 %t299, 0 + br i1 %t300, label %then62, label %ifend64 +then62: + %t301 = load ptr, ptr %t1 + %t302 = call ptr @fn_arg_code(ptr %t301, i32 0) + store ptr %t302, ptr %t303 + %t304 = load ptr, ptr %t303 + %t305 = call ptr @fn_sconcat(ptr %t304, ptr @.str424) + %t306 = call ptr @fn_sconcat(ptr @.str423, ptr %t305) + %t307 = call ptr @fn_emit_bind(ptr %t306) + %t308 = call ptr @fn_val(ptr %t307, ptr @.str425) + store ptr %t308, ptr %retval + br label %ret +ifend64: + %t313 = load ptr, ptr %t0 + %t314 = call i32 @fn_streq(ptr %t313, ptr @.str426) + %t315 = icmp ne i32 %t314, 0 + %t316 = zext i1 %t315 to i32 + store i32 %t316, ptr %t312 + br i1 %t315, label %scend66, label %sc65 +sc65: + %t317 = load ptr, ptr %t0 + %t318 = call i32 @fn_streq(ptr %t317, ptr @.str427) + %t319 = icmp ne i32 %t318, 0 + %t320 = zext i1 %t319 to i32 + store i32 %t320, ptr %t312 + br label %scend66 +scend66: + %t321 = load i32, ptr %t312 + %t322 = icmp ne i32 %t321, 0 + %t323 = zext i1 %t322 to i32 + store i32 %t323, ptr %t311 + br i1 %t322, label %scend68, label %sc67 +sc67: + %t324 = load ptr, ptr %t0 + %t325 = call i32 @fn_streq(ptr %t324, ptr @.str428) + %t326 = icmp ne i32 %t325, 0 + %t327 = zext i1 %t326 to i32 + store i32 %t327, ptr %t311 + br label %scend68 +scend68: + %t328 = load i32, ptr %t311 + %t329 = icmp ne i32 %t328, 0 + %t330 = zext i1 %t329 to i32 + store i32 %t330, ptr %t310 + br i1 %t329, label %scend70, label %sc69 +sc69: + %t331 = load ptr, ptr %t0 + %t332 = call i32 @fn_streq(ptr %t331, ptr @.str429) + %t333 = icmp ne i32 %t332, 0 + %t334 = zext i1 %t333 to i32 + store i32 %t334, ptr %t310 + br label %scend70 +scend70: + %t335 = load i32, ptr %t310 + %t336 = icmp ne i32 %t335, 0 + %t337 = zext i1 %t336 to i32 + store i32 %t337, ptr %t309 + br i1 %t336, label %scend72, label %sc71 +sc71: + %t338 = load ptr, ptr %t0 + %t339 = call i32 @fn_streq(ptr %t338, ptr @.str430) + %t340 = icmp ne i32 %t339, 0 + %t341 = zext i1 %t340 to i32 + store i32 %t341, ptr %t309 + br label %scend72 +scend72: + %t342 = load i32, ptr %t309 + %t343 = icmp ne i32 %t342, 0 + br i1 %t343, label %then73, label %ifend75 +then73: + %t344 = load ptr, ptr %t1 + %t345 = call ptr @fn_arg_code(ptr %t344, i32 0) + store ptr %t345, ptr %t346 + %t347 = load ptr, ptr %t1 + %t348 = call ptr @fn_arg_code(ptr %t347, i32 1) + store ptr %t348, ptr %t349 + store ptr @.str431, ptr %t350 + %t351 = load ptr, ptr %t0 + %t352 = call i32 @fn_streq(ptr %t351, ptr @.str432) + %t353 = icmp ne i32 %t352, 0 + br i1 %t353, label %then76, label %ifend78 +then76: + store ptr @.str433, ptr %t350 + br label %ifend78 +ifend78: + %t354 = load ptr, ptr %t0 + %t355 = call i32 @fn_streq(ptr %t354, ptr @.str434) + %t356 = icmp ne i32 %t355, 0 + br i1 %t356, label %then79, label %ifend81 +then79: + store ptr @.str435, ptr %t350 + br label %ifend81 +ifend81: + %t357 = load ptr, ptr %t0 + %t358 = call i32 @fn_streq(ptr %t357, ptr @.str436) + %t359 = icmp ne i32 %t358, 0 + br i1 %t359, label %then82, label %ifend84 +then82: + store ptr @.str437, ptr %t350 + br label %ifend84 +ifend84: + %t360 = load ptr, ptr %t0 + %t361 = call i32 @fn_streq(ptr %t360, ptr @.str438) + %t362 = icmp ne i32 %t361, 0 + br i1 %t362, label %then85, label %ifend87 +then85: + store ptr @.str439, ptr %t350 + br label %ifend87 +ifend87: + %t363 = load ptr, ptr %t350 + %t364 = load ptr, ptr %t346 + %t365 = load ptr, ptr %t349 + %t366 = call ptr @fn_sconcat(ptr @.str441, ptr %t365) + %t367 = call ptr @fn_sconcat(ptr %t364, ptr %t366) + %t368 = call ptr @fn_sconcat(ptr @.str440, ptr %t367) + %t369 = call ptr @fn_sconcat(ptr %t363, ptr %t368) + %t370 = call ptr @fn_emit_bind(ptr %t369) + %t371 = call ptr @fn_val(ptr %t370, ptr @.str442) + store ptr %t371, ptr %retval + br label %ret +ifend75: + %t372 = load ptr, ptr %t0 + %t373 = call i32 @fn_streq(ptr %t372, ptr @.str443) + %t374 = icmp ne i32 %t373, 0 + br i1 %t374, label %then88, label %ifend90 +then88: + %t375 = load ptr, ptr %t1 + %t376 = call ptr @fn_arg_code(ptr %t375, i32 0) + store ptr %t376, ptr %t377 + %t378 = load ptr, ptr %t1 + %t379 = call ptr @fn_arg_code(ptr %t378, i32 1) + store ptr %t379, ptr %t380 + %t381 = call ptr @fn_nreg() + store ptr %t381, ptr %t382 + call void @fn_emit(ptr @.str444) + %t383 = load ptr, ptr %t382 + call void @fn_emit(ptr %t383) + call void @fn_emit(ptr @.str445) + %t384 = load ptr, ptr %t377 + call void @fn_emit(ptr %t384) + call void @fn_emit(ptr @.str446) + %t385 = load ptr, ptr %t380 + call void @fn_emit(ptr %t385) + call void @fn_emit(ptr @.str447) + %t386 = load ptr, ptr %t382 + %t387 = call ptr @fn_sconcat(ptr @.str448, ptr %t386) + %t388 = call ptr @fn_emit_bind(ptr %t387) + %t389 = call ptr @fn_val(ptr %t388, ptr @.str449) + store ptr %t389, ptr %retval + br label %ret +ifend90: + %t390 = load ptr, ptr %t0 + %t391 = call i32 @fn_streq(ptr %t390, ptr @.str450) + %t392 = icmp ne i32 %t391, 0 + br i1 %t392, label %then91, label %ifend93 +then91: + %t393 = load ptr, ptr %t1 + %t394 = call ptr @fn_arg_code(ptr %t393, i32 0) + store ptr %t394, ptr %t395 + %t396 = load ptr, ptr %t1 + %t397 = call ptr @fn_arg_code(ptr %t396, i32 1) + store ptr %t397, ptr %t398 + %t399 = load ptr, ptr %t1 + %t400 = call ptr @fn_arg_code(ptr %t399, i32 2) + store ptr %t400, ptr %t401 + %t402 = call ptr @fn_nreg() + store ptr %t402, ptr %t403 + call void @fn_emit(ptr @.str451) + %t404 = load ptr, ptr %t403 + call void @fn_emit(ptr %t404) + call void @fn_emit(ptr @.str452) + %t405 = load ptr, ptr %t395 + call void @fn_emit(ptr %t405) + call void @fn_emit(ptr @.str453) + %t406 = load ptr, ptr %t398 + call void @fn_emit(ptr %t406) + call void @fn_emit(ptr @.str454) + call void @fn_emit(ptr @.str455) + %t407 = load ptr, ptr %t401 + call void @fn_emit(ptr %t407) + call void @fn_emit(ptr @.str456) + %t408 = load ptr, ptr %t403 + call void @fn_emit(ptr %t408) + call void @fn_emit(ptr @.str457) + %t409 = call ptr @fn_val(ptr @.str458, ptr @.str459) + store ptr %t409, ptr %retval + br label %ret +ifend93: + store i32 0, ptr @g_g_intrin_ok + %t410 = call ptr @fn_val(ptr @.str460, ptr @.str461) + store ptr %t410, ptr %retval + br label %ret +ret: + %t411 = load ptr, ptr %retval + ret ptr %t411 +} + +define i32 @fn_is_intrinsic2(ptr %arg_name) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t20 = alloca i32 + %t21 = alloca i32 + %t39 = alloca i32 + %t50 = alloca i32 + %t51 = alloca i32 + %t52 = alloca i32 + %t77 = alloca i32 + %t88 = alloca i32 + %t99 = alloca i32 + %t100 = alloca i32 + %t118 = alloca i32 + store ptr %arg_name, ptr %t0 + %t3 = load ptr, ptr %t0 + %t4 = call i32 @fn_streq(ptr %t3, ptr @.str462) + %t5 = icmp ne i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + store i32 %t6, ptr %t2 + br i1 %t5, label %scend1, label %sc0 +sc0: + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str463) + %t9 = icmp ne i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + store i32 %t10, ptr %t2 + br label %scend1 +scend1: + %t11 = load i32, ptr %t2 + %t12 = icmp ne i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + store i32 %t13, ptr %t1 + br i1 %t12, label %scend3, label %sc2 +sc2: + %t14 = load ptr, ptr %t0 + %t15 = call i32 @fn_streq(ptr %t14, ptr @.str464) + %t16 = icmp ne i32 %t15, 0 + %t17 = zext i1 %t16 to i32 + store i32 %t17, ptr %t1 + br label %scend3 +scend3: + %t18 = load i32, ptr %t1 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then4, label %ifend6 +then4: + store i32 1, ptr %retval + br label %ret +ifend6: + %t22 = load ptr, ptr %t0 + %t23 = call i32 @fn_streq(ptr %t22, ptr @.str465) + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t21 + br i1 %t24, label %scend8, label %sc7 +sc7: + %t26 = load ptr, ptr %t0 + %t27 = call i32 @fn_streq(ptr %t26, ptr @.str466) + %t28 = icmp ne i32 %t27, 0 + %t29 = zext i1 %t28 to i32 + store i32 %t29, ptr %t21 + br label %scend8 +scend8: + %t30 = load i32, ptr %t21 + %t31 = icmp ne i32 %t30, 0 + %t32 = zext i1 %t31 to i32 + store i32 %t32, ptr %t20 + br i1 %t31, label %scend10, label %sc9 +sc9: + %t33 = load ptr, ptr %t0 + %t34 = call i32 @fn_streq(ptr %t33, ptr @.str467) + %t35 = icmp ne i32 %t34, 0 + %t36 = zext i1 %t35 to i32 + store i32 %t36, ptr %t20 + br label %scend10 +scend10: + %t37 = load i32, ptr %t20 + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %then11, label %ifend13 +then11: + store i32 1, ptr %retval + br label %ret +ifend13: + %t40 = load ptr, ptr %t0 + %t41 = call i32 @fn_streq(ptr %t40, ptr @.str468) + %t42 = icmp ne i32 %t41, 0 + %t43 = zext i1 %t42 to i32 + store i32 %t43, ptr %t39 + br i1 %t42, label %scend15, label %sc14 +sc14: + %t44 = load ptr, ptr %t0 + %t45 = call i32 @fn_streq(ptr %t44, ptr @.str469) + %t46 = icmp ne i32 %t45, 0 + %t47 = zext i1 %t46 to i32 + store i32 %t47, ptr %t39 + br label %scend15 +scend15: + %t48 = load i32, ptr %t39 + %t49 = icmp ne i32 %t48, 0 + br i1 %t49, label %then16, label %ifend18 +then16: + store i32 1, ptr %retval + br label %ret +ifend18: + %t53 = load ptr, ptr %t0 + %t54 = call i32 @fn_streq(ptr %t53, ptr @.str470) + %t55 = icmp ne i32 %t54, 0 + %t56 = zext i1 %t55 to i32 + store i32 %t56, ptr %t52 + br i1 %t55, label %scend20, label %sc19 +sc19: + %t57 = load ptr, ptr %t0 + %t58 = call i32 @fn_streq(ptr %t57, ptr @.str471) + %t59 = icmp ne i32 %t58, 0 + %t60 = zext i1 %t59 to i32 + store i32 %t60, ptr %t52 + br label %scend20 +scend20: + %t61 = load i32, ptr %t52 + %t62 = icmp ne i32 %t61, 0 + %t63 = zext i1 %t62 to i32 + store i32 %t63, ptr %t51 + br i1 %t62, label %scend22, label %sc21 +sc21: + %t64 = load ptr, ptr %t0 + %t65 = call i32 @fn_streq(ptr %t64, ptr @.str472) + %t66 = icmp ne i32 %t65, 0 + %t67 = zext i1 %t66 to i32 + store i32 %t67, ptr %t51 + br label %scend22 +scend22: + %t68 = load i32, ptr %t51 + %t69 = icmp ne i32 %t68, 0 + %t70 = zext i1 %t69 to i32 + store i32 %t70, ptr %t50 + br i1 %t69, label %scend24, label %sc23 +sc23: + %t71 = load ptr, ptr %t0 + %t72 = call i32 @fn_streq(ptr %t71, ptr @.str473) + %t73 = icmp ne i32 %t72, 0 + %t74 = zext i1 %t73 to i32 + store i32 %t74, ptr %t50 + br label %scend24 +scend24: + %t75 = load i32, ptr %t50 + %t76 = icmp ne i32 %t75, 0 + br i1 %t76, label %then25, label %ifend27 +then25: + store i32 1, ptr %retval + br label %ret +ifend27: + %t78 = load ptr, ptr %t0 + %t79 = call i32 @fn_streq(ptr %t78, ptr @.str474) + %t80 = icmp ne i32 %t79, 0 + %t81 = zext i1 %t80 to i32 + store i32 %t81, ptr %t77 + br i1 %t80, label %scend29, label %sc28 +sc28: + %t82 = load ptr, ptr %t0 + %t83 = call i32 @fn_streq(ptr %t82, ptr @.str475) + %t84 = icmp ne i32 %t83, 0 + %t85 = zext i1 %t84 to i32 + store i32 %t85, ptr %t77 + br label %scend29 +scend29: + %t86 = load i32, ptr %t77 + %t87 = icmp ne i32 %t86, 0 + br i1 %t87, label %then30, label %ifend32 +then30: + store i32 1, ptr %retval + br label %ret +ifend32: + %t89 = load ptr, ptr %t0 + %t90 = call i32 @fn_streq(ptr %t89, ptr @.str476) + %t91 = icmp ne i32 %t90, 0 + %t92 = zext i1 %t91 to i32 + store i32 %t92, ptr %t88 + br i1 %t91, label %scend34, label %sc33 +sc33: + %t93 = load ptr, ptr %t0 + %t94 = call i32 @fn_streq(ptr %t93, ptr @.str477) + %t95 = icmp ne i32 %t94, 0 + %t96 = zext i1 %t95 to i32 + store i32 %t96, ptr %t88 + br label %scend34 +scend34: + %t97 = load i32, ptr %t88 + %t98 = icmp ne i32 %t97, 0 + br i1 %t98, label %then35, label %ifend37 +then35: + store i32 1, ptr %retval + br label %ret +ifend37: + %t101 = load ptr, ptr %t0 + %t102 = call i32 @fn_streq(ptr %t101, ptr @.str478) + %t103 = icmp ne i32 %t102, 0 + %t104 = zext i1 %t103 to i32 + store i32 %t104, ptr %t100 + br i1 %t103, label %scend39, label %sc38 +sc38: + %t105 = load ptr, ptr %t0 + %t106 = call i32 @fn_streq(ptr %t105, ptr @.str479) + %t107 = icmp ne i32 %t106, 0 + %t108 = zext i1 %t107 to i32 + store i32 %t108, ptr %t100 + br label %scend39 +scend39: + %t109 = load i32, ptr %t100 + %t110 = icmp ne i32 %t109, 0 + %t111 = zext i1 %t110 to i32 + store i32 %t111, ptr %t99 + br i1 %t110, label %scend41, label %sc40 +sc40: + %t112 = load ptr, ptr %t0 + %t113 = call i32 @fn_streq(ptr %t112, ptr @.str480) + %t114 = icmp ne i32 %t113, 0 + %t115 = zext i1 %t114 to i32 + store i32 %t115, ptr %t99 + br label %scend41 +scend41: + %t116 = load i32, ptr %t99 + %t117 = icmp ne i32 %t116, 0 + br i1 %t117, label %then42, label %ifend44 +then42: + store i32 1, ptr %retval + br label %ret +ifend44: + %t119 = load ptr, ptr %t0 + %t120 = call i32 @fn_streq(ptr %t119, ptr @.str481) + %t121 = icmp ne i32 %t120, 0 + %t122 = zext i1 %t121 to i32 + store i32 %t122, ptr %t118 + br i1 %t121, label %scend46, label %sc45 +sc45: + %t123 = load ptr, ptr %t0 + %t124 = call i32 @fn_streq(ptr %t123, ptr @.str482) + %t125 = icmp ne i32 %t124, 0 + %t126 = zext i1 %t125 to i32 + store i32 %t126, ptr %t118 + br label %scend46 +scend46: + %t127 = load i32, ptr %t118 + %t128 = icmp ne i32 %t127, 0 + br i1 %t128, label %then47, label %ifend49 +then47: + store i32 1, ptr %retval + br label %ret +ifend49: + store i32 0, ptr %retval + br label %ret +ret: + %t129 = load i32, ptr %retval + ret i32 %t129 +} + +define ptr @fn_emit_intrinsic2(ptr %arg_name, ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t7 = alloca ptr + %t15 = alloca ptr + %t18 = alloca ptr + %t21 = alloca ptr + %t26 = alloca ptr + %t36 = alloca ptr + %t39 = alloca ptr + %t42 = alloca ptr + %t47 = alloca ptr + %t57 = alloca ptr + %t60 = alloca ptr + %t62 = alloca ptr + %t78 = alloca ptr + %t86 = alloca ptr + %t91 = alloca ptr + %t101 = alloca ptr + %t112 = alloca ptr + %t115 = alloca ptr + %t117 = alloca ptr + %t130 = alloca ptr + %t133 = alloca ptr + %t136 = alloca ptr + %t138 = alloca ptr + %t150 = alloca ptr + %t153 = alloca ptr + %t155 = alloca ptr + %t168 = alloca ptr + %t171 = alloca ptr + %t174 = alloca ptr + %t176 = alloca ptr + %t194 = alloca ptr + %t210 = alloca ptr + %t241 = alloca ptr + %t244 = alloca ptr + %t247 = alloca ptr + %t250 = alloca ptr + %t261 = alloca ptr + %t264 = alloca ptr + %t267 = alloca ptr + store ptr %arg_name, ptr %t0 + store ptr %arg_e, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = call i32 @fn_streq(ptr %t2, ptr @.str483) + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + %t5 = load ptr, ptr %t1 + %t6 = call ptr @fn_arg_code(ptr %t5, i32 0) + store ptr %t6, ptr %t7 + call void @fn_emit(ptr @.str484) + %t8 = load ptr, ptr %t7 + call void @fn_emit(ptr %t8) + call void @fn_emit(ptr @.str485) + %t9 = call ptr @fn_val(ptr @.str486, ptr @.str487) + store ptr %t9, ptr %retval + br label %ret +ifend2: + %t10 = load ptr, ptr %t0 + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str488) + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then3, label %ifend5 +then3: + %t13 = load ptr, ptr %t1 + %t14 = call ptr @fn_arg_code(ptr %t13, i32 0) + store ptr %t14, ptr %t15 + %t16 = load ptr, ptr %t1 + %t17 = call ptr @fn_arg_code(ptr %t16, i32 1) + store ptr %t17, ptr %t18 + %t19 = load ptr, ptr %t1 + %t20 = call ptr @fn_arg_code(ptr %t19, i32 2) + store ptr %t20, ptr %t21 + %t22 = load ptr, ptr %t21 + %t23 = call ptr @fn_sconcat(ptr %t22, ptr @.str490) + %t24 = call ptr @fn_sconcat(ptr @.str489, ptr %t23) + %t25 = call ptr @fn_emit_bind(ptr %t24) + store ptr %t25, ptr %t26 + call void @fn_emit(ptr @.str491) + %t27 = load ptr, ptr %t15 + call void @fn_emit(ptr %t27) + call void @fn_emit(ptr @.str492) + %t28 = load ptr, ptr %t18 + call void @fn_emit(ptr %t28) + call void @fn_emit(ptr @.str493) + %t29 = load ptr, ptr %t26 + call void @fn_emit(ptr %t29) + call void @fn_emit(ptr @.str494) + %t30 = call ptr @fn_val(ptr @.str495, ptr @.str496) + store ptr %t30, ptr %retval + br label %ret +ifend5: + %t31 = load ptr, ptr %t0 + %t32 = call i32 @fn_streq(ptr %t31, ptr @.str497) + %t33 = icmp ne i32 %t32, 0 + br i1 %t33, label %then6, label %ifend8 +then6: + %t34 = load ptr, ptr %t1 + %t35 = call ptr @fn_arg_code(ptr %t34, i32 0) + store ptr %t35, ptr %t36 + %t37 = load ptr, ptr %t1 + %t38 = call ptr @fn_arg_code(ptr %t37, i32 1) + store ptr %t38, ptr %t39 + %t40 = load ptr, ptr %t1 + %t41 = call ptr @fn_arg_code(ptr %t40, i32 2) + store ptr %t41, ptr %t42 + %t43 = load ptr, ptr %t42 + %t44 = call ptr @fn_sconcat(ptr %t43, ptr @.str499) + %t45 = call ptr @fn_sconcat(ptr @.str498, ptr %t44) + %t46 = call ptr @fn_emit_bind(ptr %t45) + store ptr %t46, ptr %t47 + call void @fn_emit(ptr @.str500) + %t48 = load ptr, ptr %t36 + call void @fn_emit(ptr %t48) + call void @fn_emit(ptr @.str501) + %t49 = load ptr, ptr %t39 + call void @fn_emit(ptr %t49) + call void @fn_emit(ptr @.str502) + %t50 = load ptr, ptr %t47 + call void @fn_emit(ptr %t50) + call void @fn_emit(ptr @.str503) + %t51 = call ptr @fn_val(ptr @.str504, ptr @.str505) + store ptr %t51, ptr %retval + br label %ret +ifend8: + %t52 = load ptr, ptr %t0 + %t53 = call i32 @fn_streq(ptr %t52, ptr @.str506) + %t54 = icmp ne i32 %t53, 0 + br i1 %t54, label %then9, label %ifend11 +then9: + %t55 = load ptr, ptr %t1 + %t56 = call ptr @fn_arg_code(ptr %t55, i32 0) + store ptr %t56, ptr %t57 + %t58 = load ptr, ptr %t1 + %t59 = call ptr @fn_arg_code(ptr %t58, i32 1) + store ptr %t59, ptr %t60 + %t61 = call ptr @fn_nreg() + store ptr %t61, ptr %t62 + call void @fn_emit(ptr @.str507) + %t63 = load ptr, ptr %t62 + call void @fn_emit(ptr %t63) + call void @fn_emit(ptr @.str508) + %t64 = load ptr, ptr %t57 + call void @fn_emit(ptr %t64) + call void @fn_emit(ptr @.str509) + %t65 = load ptr, ptr %t60 + call void @fn_emit(ptr %t65) + call void @fn_emit(ptr @.str510) + %t66 = load ptr, ptr %t62 + %t67 = call ptr @fn_val(ptr %t66, ptr @.str511) + store ptr %t67, ptr %retval + br label %ret +ifend11: + %t68 = load ptr, ptr %t0 + %t69 = call i32 @fn_streq(ptr %t68, ptr @.str512) + %t70 = icmp ne i32 %t69, 0 + br i1 %t70, label %then12, label %ifend14 +then12: + %t71 = call ptr @fn_emit_bind(ptr @.str513) + %t72 = call ptr @fn_val(ptr %t71, ptr @.str514) + store ptr %t72, ptr %retval + br label %ret +ifend14: + %t73 = load ptr, ptr %t0 + %t74 = call i32 @fn_streq(ptr %t73, ptr @.str515) + %t75 = icmp ne i32 %t74, 0 + br i1 %t75, label %then15, label %ifend17 +then15: + %t76 = load ptr, ptr %t1 + %t77 = call ptr @fn_arg_code(ptr %t76, i32 0) + store ptr %t77, ptr %t78 + call void @fn_emit(ptr @.str516) + %t79 = load ptr, ptr %t78 + call void @fn_emit(ptr %t79) + call void @fn_emit(ptr @.str517) + %t80 = call ptr @fn_val(ptr @.str518, ptr @.str519) + store ptr %t80, ptr %retval + br label %ret +ifend17: + %t81 = load ptr, ptr %t0 + %t82 = call i32 @fn_streq(ptr %t81, ptr @.str520) + %t83 = icmp ne i32 %t82, 0 + br i1 %t83, label %then18, label %ifend20 +then18: + %t84 = load ptr, ptr %t1 + %t85 = call ptr @fn_arg_code(ptr %t84, i32 0) + store ptr %t85, ptr %t86 + %t87 = load ptr, ptr %t86 + %t88 = call ptr @fn_sconcat(ptr %t87, ptr @.str522) + %t89 = call ptr @fn_sconcat(ptr @.str521, ptr %t88) + %t90 = call ptr @fn_emit_bind(ptr %t89) + store ptr %t90, ptr %t91 + %t92 = load ptr, ptr %t91 + %t93 = call ptr @fn_sconcat(ptr %t92, ptr @.str524) + %t94 = call ptr @fn_sconcat(ptr @.str523, ptr %t93) + %t95 = call ptr @fn_emit_bind(ptr %t94) + %t96 = call ptr @fn_val(ptr %t95, ptr @.str525) + store ptr %t96, ptr %retval + br label %ret +ifend20: + %t97 = load ptr, ptr %t0 + %t98 = call i32 @fn_streq(ptr %t97, ptr @.str526) + %t99 = icmp ne i32 %t98, 0 + br i1 %t99, label %then21, label %ifend23 +then21: + %t100 = call ptr @fn_emit_bind(ptr @.str527) + store ptr %t100, ptr %t101 + %t102 = load ptr, ptr %t101 + %t103 = call ptr @fn_sconcat(ptr %t102, ptr @.str529) + %t104 = call ptr @fn_sconcat(ptr @.str528, ptr %t103) + %t105 = call ptr @fn_emit_bind(ptr %t104) + %t106 = call ptr @fn_val(ptr %t105, ptr @.str530) + store ptr %t106, ptr %retval + br label %ret +ifend23: + %t107 = load ptr, ptr %t0 + %t108 = call i32 @fn_streq(ptr %t107, ptr @.str531) + %t109 = icmp ne i32 %t108, 0 + br i1 %t109, label %then24, label %ifend26 +then24: + %t110 = load ptr, ptr %t1 + %t111 = call ptr @fn_arg_code(ptr %t110, i32 0) + store ptr %t111, ptr %t112 + %t113 = load ptr, ptr %t1 + %t114 = call ptr @fn_arg_code(ptr %t113, i32 1) + store ptr %t114, ptr %t115 + %t116 = call ptr @fn_nreg() + store ptr %t116, ptr %t117 + call void @fn_emit(ptr @.str532) + %t118 = load ptr, ptr %t117 + call void @fn_emit(ptr %t118) + call void @fn_emit(ptr @.str533) + %t119 = load ptr, ptr %t112 + call void @fn_emit(ptr %t119) + call void @fn_emit(ptr @.str534) + %t120 = load ptr, ptr %t115 + call void @fn_emit(ptr %t120) + call void @fn_emit(ptr @.str535) + %t121 = load ptr, ptr %t117 + %t122 = call ptr @fn_sconcat(ptr @.str536, ptr %t121) + %t123 = call ptr @fn_emit_bind(ptr %t122) + %t124 = call ptr @fn_val(ptr %t123, ptr @.str537) + store ptr %t124, ptr %retval + br label %ret +ifend26: + %t125 = load ptr, ptr %t0 + %t126 = call i32 @fn_streq(ptr %t125, ptr @.str538) + %t127 = icmp ne i32 %t126, 0 + br i1 %t127, label %then27, label %ifend29 +then27: + %t128 = load ptr, ptr %t1 + %t129 = call ptr @fn_arg_code(ptr %t128, i32 0) + store ptr %t129, ptr %t130 + %t131 = load ptr, ptr %t1 + %t132 = call ptr @fn_arg_code(ptr %t131, i32 1) + store ptr %t132, ptr %t133 + %t134 = load ptr, ptr %t1 + %t135 = call ptr @fn_arg_code(ptr %t134, i32 2) + store ptr %t135, ptr %t136 + %t137 = call ptr @fn_nreg() + store ptr %t137, ptr %t138 + call void @fn_emit(ptr @.str539) + %t139 = load ptr, ptr %t138 + call void @fn_emit(ptr %t139) + call void @fn_emit(ptr @.str540) + %t140 = load ptr, ptr %t130 + call void @fn_emit(ptr %t140) + call void @fn_emit(ptr @.str541) + %t141 = load ptr, ptr %t133 + call void @fn_emit(ptr %t141) + call void @fn_emit(ptr @.str542) + call void @fn_emit(ptr @.str543) + %t142 = load ptr, ptr %t136 + call void @fn_emit(ptr %t142) + call void @fn_emit(ptr @.str544) + %t143 = load ptr, ptr %t138 + call void @fn_emit(ptr %t143) + call void @fn_emit(ptr @.str545) + %t144 = call ptr @fn_val(ptr @.str546, ptr @.str547) + store ptr %t144, ptr %retval + br label %ret +ifend29: + %t145 = load ptr, ptr %t0 + %t146 = call i32 @fn_streq(ptr %t145, ptr @.str548) + %t147 = icmp ne i32 %t146, 0 + br i1 %t147, label %then30, label %ifend32 +then30: + %t148 = load ptr, ptr %t1 + %t149 = call ptr @fn_arg_code(ptr %t148, i32 0) + store ptr %t149, ptr %t150 + %t151 = load ptr, ptr %t1 + %t152 = call ptr @fn_arg_code(ptr %t151, i32 1) + store ptr %t152, ptr %t153 + %t154 = call ptr @fn_nreg() + store ptr %t154, ptr %t155 + call void @fn_emit(ptr @.str549) + %t156 = load ptr, ptr %t155 + call void @fn_emit(ptr %t156) + call void @fn_emit(ptr @.str550) + %t157 = load ptr, ptr %t150 + call void @fn_emit(ptr %t157) + call void @fn_emit(ptr @.str551) + %t158 = load ptr, ptr %t153 + call void @fn_emit(ptr %t158) + call void @fn_emit(ptr @.str552) + %t159 = load ptr, ptr %t155 + %t160 = call ptr @fn_sconcat(ptr @.str553, ptr %t159) + %t161 = call ptr @fn_emit_bind(ptr %t160) + %t162 = call ptr @fn_val(ptr %t161, ptr @.str554) + store ptr %t162, ptr %retval + br label %ret +ifend32: + %t163 = load ptr, ptr %t0 + %t164 = call i32 @fn_streq(ptr %t163, ptr @.str555) + %t165 = icmp ne i32 %t164, 0 + br i1 %t165, label %then33, label %ifend35 +then33: + %t166 = load ptr, ptr %t1 + %t167 = call ptr @fn_arg_code(ptr %t166, i32 0) + store ptr %t167, ptr %t168 + %t169 = load ptr, ptr %t1 + %t170 = call ptr @fn_arg_code(ptr %t169, i32 1) + store ptr %t170, ptr %t171 + %t172 = load ptr, ptr %t1 + %t173 = call ptr @fn_arg_code(ptr %t172, i32 2) + store ptr %t173, ptr %t174 + %t175 = call ptr @fn_nreg() + store ptr %t175, ptr %t176 + call void @fn_emit(ptr @.str556) + %t177 = load ptr, ptr %t176 + call void @fn_emit(ptr %t177) + call void @fn_emit(ptr @.str557) + %t178 = load ptr, ptr %t168 + call void @fn_emit(ptr %t178) + call void @fn_emit(ptr @.str558) + %t179 = load ptr, ptr %t171 + call void @fn_emit(ptr %t179) + call void @fn_emit(ptr @.str559) + call void @fn_emit(ptr @.str560) + %t180 = load ptr, ptr %t174 + call void @fn_emit(ptr %t180) + call void @fn_emit(ptr @.str561) + %t181 = load ptr, ptr %t176 + call void @fn_emit(ptr %t181) + call void @fn_emit(ptr @.str562) + %t182 = call ptr @fn_val(ptr @.str563, ptr @.str564) + store ptr %t182, ptr %retval + br label %ret +ifend35: + %t183 = load ptr, ptr %t0 + %t184 = call i32 @fn_streq(ptr %t183, ptr @.str565) + %t185 = icmp ne i32 %t184, 0 + br i1 %t185, label %then36, label %ifend38 +then36: + %t186 = load ptr, ptr %t1 + %t187 = getelementptr inbounds %Str_Node, ptr %t186, i32 0, i32 7 + %t188 = load ptr, ptr %t187 + %t189 = getelementptr inbounds %LSlice, ptr %t188, i32 0, i32 0 + %t190 = load ptr, ptr %t189 + %t191 = getelementptr inbounds ptr, ptr %t190, i32 0 + %t192 = load ptr, ptr %t191 + %t193 = call ptr @fn_emit_expr(ptr %t192) + store ptr %t193, ptr %t194 + %t195 = load ptr, ptr %t194 + %t196 = getelementptr inbounds %Str_Val, ptr %t195, i32 0, i32 0 + %t197 = load ptr, ptr %t196 + %t198 = call ptr @fn_val(ptr %t197, ptr @.str566) + store ptr %t198, ptr %retval + br label %ret +ifend38: + %t199 = load ptr, ptr %t0 + %t200 = call i32 @fn_streq(ptr %t199, ptr @.str567) + %t201 = icmp ne i32 %t200, 0 + br i1 %t201, label %then39, label %ifend41 +then39: + %t202 = load ptr, ptr %t1 + %t203 = getelementptr inbounds %Str_Node, ptr %t202, i32 0, i32 7 + %t204 = load ptr, ptr %t203 + %t205 = getelementptr inbounds %LSlice, ptr %t204, i32 0, i32 0 + %t206 = load ptr, ptr %t205 + %t207 = getelementptr inbounds ptr, ptr %t206, i32 0 + %t208 = load ptr, ptr %t207 + %t209 = call ptr @fn_emit_expr(ptr %t208) + store ptr %t209, ptr %t210 + %t211 = load ptr, ptr %t210 + %t212 = getelementptr inbounds %Str_Val, ptr %t211, i32 0, i32 0 + %t213 = load ptr, ptr %t212 + %t214 = call ptr @fn_val(ptr %t213, ptr @.str568) + store ptr %t214, ptr %retval + br label %ret +ifend41: + %t215 = load ptr, ptr %t0 + %t216 = call i32 @fn_streq(ptr %t215, ptr @.str569) + %t217 = icmp ne i32 %t216, 0 + br i1 %t217, label %then42, label %ifend44 +then42: + %t218 = load i32, ptr @g_g_windowed + %t219 = icmp ne i32 %t218, 0 + br i1 %t219, label %then45, label %ifend47 +then45: + %t220 = call ptr @fn_val(ptr @.str570, ptr @.str571) + store ptr %t220, ptr %retval + br label %ret +ifend47: + %t221 = call ptr @fn_val(ptr @.str572, ptr @.str573) + store ptr %t221, ptr %retval + br label %ret +ifend44: + %t222 = load ptr, ptr %t0 + %t223 = call i32 @fn_streq(ptr %t222, ptr @.str574) + %t224 = icmp ne i32 %t223, 0 + br i1 %t224, label %then48, label %ifend50 +then48: + %t225 = call ptr @fn_val(ptr @.str575, ptr @.str576) + store ptr %t225, ptr %retval + br label %ret +ifend50: + %t226 = load ptr, ptr %t0 + %t227 = call i32 @fn_streq(ptr %t226, ptr @.str577) + %t228 = icmp ne i32 %t227, 0 + br i1 %t228, label %then51, label %ifend53 +then51: + %t229 = call ptr @fn_emit_bind(ptr @.str578) + %t230 = call ptr @fn_val(ptr %t229, ptr @.str579) + store ptr %t230, ptr %retval + br label %ret +ifend53: + %t231 = load ptr, ptr %t0 + %t232 = call i32 @fn_streq(ptr %t231, ptr @.str580) + %t233 = icmp ne i32 %t232, 0 + br i1 %t233, label %then54, label %ifend56 +then54: + %t234 = call ptr @fn_emit_bind(ptr @.str581) + %t235 = call ptr @fn_val(ptr %t234, ptr @.str582) + store ptr %t235, ptr %retval + br label %ret +ifend56: + %t236 = load ptr, ptr %t0 + %t237 = call i32 @fn_streq(ptr %t236, ptr @.str583) + %t238 = icmp ne i32 %t237, 0 + br i1 %t238, label %then57, label %ifend59 +then57: + %t239 = load ptr, ptr %t1 + %t240 = call ptr @fn_arg_code(ptr %t239, i32 0) + store ptr %t240, ptr %t241 + %t242 = load ptr, ptr %t1 + %t243 = call ptr @fn_arg_code(ptr %t242, i32 1) + store ptr %t243, ptr %t244 + %t245 = load ptr, ptr %t1 + %t246 = call ptr @fn_arg_code(ptr %t245, i32 2) + store ptr %t246, ptr %t247 + %t248 = load ptr, ptr %t1 + %t249 = call ptr @fn_arg_code(ptr %t248, i32 3) + store ptr %t249, ptr %t250 + call void @fn_emit(ptr @.str584) + %t251 = load ptr, ptr %t241 + call void @fn_emit(ptr %t251) + call void @fn_emit(ptr @.str585) + %t252 = load ptr, ptr %t244 + call void @fn_emit(ptr %t252) + call void @fn_emit(ptr @.str586) + %t253 = load ptr, ptr %t247 + call void @fn_emit(ptr %t253) + call void @fn_emit(ptr @.str587) + %t254 = load ptr, ptr %t250 + call void @fn_emit(ptr %t254) + call void @fn_emit(ptr @.str588) + %t255 = call ptr @fn_val(ptr @.str589, ptr @.str590) + store ptr %t255, ptr %retval + br label %ret +ifend59: + %t256 = load ptr, ptr %t0 + %t257 = call i32 @fn_streq(ptr %t256, ptr @.str591) + %t258 = icmp ne i32 %t257, 0 + br i1 %t258, label %then60, label %ifend62 +then60: + %t259 = load ptr, ptr %t1 + %t260 = call ptr @fn_arg_code(ptr %t259, i32 0) + store ptr %t260, ptr %t261 + %t262 = load ptr, ptr %t1 + %t263 = call ptr @fn_arg_code(ptr %t262, i32 1) + store ptr %t263, ptr %t264 + %t265 = load ptr, ptr %t1 + %t266 = call ptr @fn_arg_code(ptr %t265, i32 2) + store ptr %t266, ptr %t267 + call void @fn_emit(ptr @.str592) + %t268 = load ptr, ptr %t261 + call void @fn_emit(ptr %t268) + call void @fn_emit(ptr @.str593) + %t269 = load ptr, ptr %t264 + call void @fn_emit(ptr %t269) + call void @fn_emit(ptr @.str594) + %t270 = load ptr, ptr %t267 + call void @fn_emit(ptr %t270) + call void @fn_emit(ptr @.str595) + %t271 = call ptr @fn_val(ptr @.str596, ptr @.str597) + store ptr %t271, ptr %retval + br label %ret +ifend62: + %t272 = load ptr, ptr %t0 + %t273 = call i32 @fn_streq(ptr %t272, ptr @.str598) + %t274 = icmp ne i32 %t273, 0 + br i1 %t274, label %then63, label %ifend65 +then63: + call void @fn_emit(ptr @.str599) + %t275 = call ptr @fn_val(ptr @.str600, ptr @.str601) + store ptr %t275, ptr %retval + br label %ret +ifend65: + %t276 = call ptr @fn_val(ptr @.str602, ptr @.str603) + store ptr %t276, ptr %retval + br label %ret +ret: + %t277 = load ptr, ptr %retval + ret ptr %t277 +} + +define i32 @fn_is_math_builtin(ptr %arg_name) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t3 = alloca i32 + store ptr %arg_name, ptr %t0 + %t4 = load ptr, ptr %t0 + %t5 = call i32 @fn_streq(ptr %t4, ptr @.str604) + %t6 = icmp ne i32 %t5, 0 + %t7 = zext i1 %t6 to i32 + store i32 %t7, ptr %t3 + br i1 %t6, label %scend1, label %sc0 +sc0: + %t8 = load ptr, ptr %t0 + %t9 = call i32 @fn_streq(ptr %t8, ptr @.str605) + %t10 = icmp ne i32 %t9, 0 + %t11 = zext i1 %t10 to i32 + store i32 %t11, ptr %t3 + br label %scend1 +scend1: + %t12 = load i32, ptr %t3 + %t13 = icmp ne i32 %t12, 0 + %t14 = zext i1 %t13 to i32 + store i32 %t14, ptr %t2 + br i1 %t13, label %scend3, label %sc2 +sc2: + %t15 = load ptr, ptr %t0 + %t16 = call i32 @fn_streq(ptr %t15, ptr @.str606) + %t17 = icmp ne i32 %t16, 0 + %t18 = zext i1 %t17 to i32 + store i32 %t18, ptr %t2 + br label %scend3 +scend3: + %t19 = load i32, ptr %t2 + %t20 = icmp ne i32 %t19, 0 + %t21 = zext i1 %t20 to i32 + store i32 %t21, ptr %t1 + br i1 %t20, label %scend5, label %sc4 +sc4: + %t22 = load ptr, ptr %t0 + %t23 = call i32 @fn_streq(ptr %t22, ptr @.str607) + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t1 + br label %scend5 +scend5: + %t26 = load i32, ptr %t1 + store i32 %t26, ptr %retval + br label %ret +ret: + %t27 = load i32, ptr %retval + ret i32 %t27 +} + +define ptr @fn_emit_math_builtin(ptr %arg_name, ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t13 = alloca ptr + %t20 = alloca ptr + %t26 = alloca ptr + %t39 = alloca i32 + %t58 = alloca ptr + %t67 = alloca ptr + %t68 = alloca ptr + %t85 = alloca ptr + %t108 = alloca ptr + %t117 = alloca ptr + %t126 = alloca ptr + %t137 = alloca ptr + %t151 = alloca ptr + %t160 = alloca ptr + store ptr %arg_name, ptr %t0 + store ptr %arg_e, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = call i32 @fn_streq(ptr %t2, ptr @.str608) + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + %t5 = load ptr, ptr %t1 + %t6 = getelementptr inbounds %Str_Node, ptr %t5, i32 0, i32 7 + %t7 = load ptr, ptr %t6 + %t8 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 0 + %t9 = load ptr, ptr %t8 + %t10 = getelementptr inbounds ptr, ptr %t9, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = call ptr @fn_emit_expr(ptr %t11) + store ptr %t12, ptr %t13 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %Str_Val, ptr %t14, i32 0, i32 0 + %t16 = load ptr, ptr %t15 + %t17 = call ptr @fn_sconcat(ptr %t16, ptr @.str610) + %t18 = call ptr @fn_sconcat(ptr @.str609, ptr %t17) + %t19 = call ptr @fn_emit_bind(ptr %t18) + store ptr %t19, ptr %t20 + %t21 = load ptr, ptr %t13 + %t22 = getelementptr inbounds %Str_Val, ptr %t21, i32 0, i32 0 + %t23 = load ptr, ptr %t22 + %t24 = call ptr @fn_sconcat(ptr @.str611, ptr %t23) + %t25 = call ptr @fn_emit_bind(ptr %t24) + store ptr %t25, ptr %t26 + %t27 = load ptr, ptr %t20 + %t28 = load ptr, ptr %t26 + %t29 = load ptr, ptr %t13 + %t30 = getelementptr inbounds %Str_Val, ptr %t29, i32 0, i32 0 + %t31 = load ptr, ptr %t30 + %t32 = call ptr @fn_sconcat(ptr @.str614, ptr %t31) + %t33 = call ptr @fn_sconcat(ptr %t28, ptr %t32) + %t34 = call ptr @fn_sconcat(ptr @.str613, ptr %t33) + %t35 = call ptr @fn_sconcat(ptr %t27, ptr %t34) + %t36 = call ptr @fn_sconcat(ptr @.str612, ptr %t35) + %t37 = call ptr @fn_emit_bind(ptr %t36) + %t38 = call ptr @fn_val(ptr %t37, ptr @.str615) + store ptr %t38, ptr %retval + br label %ret +ifend2: + %t40 = load ptr, ptr %t0 + %t41 = call i32 @fn_streq(ptr %t40, ptr @.str616) + %t42 = icmp ne i32 %t41, 0 + %t43 = zext i1 %t42 to i32 + store i32 %t43, ptr %t39 + br i1 %t42, label %scend4, label %sc3 +sc3: + %t44 = load ptr, ptr %t0 + %t45 = call i32 @fn_streq(ptr %t44, ptr @.str617) + %t46 = icmp ne i32 %t45, 0 + %t47 = zext i1 %t46 to i32 + store i32 %t47, ptr %t39 + br label %scend4 +scend4: + %t48 = load i32, ptr %t39 + %t49 = icmp ne i32 %t48, 0 + br i1 %t49, label %then5, label %ifend7 +then5: + %t50 = load ptr, ptr %t1 + %t51 = getelementptr inbounds %Str_Node, ptr %t50, i32 0, i32 7 + %t52 = load ptr, ptr %t51 + %t53 = getelementptr inbounds %LSlice, ptr %t52, i32 0, i32 0 + %t54 = load ptr, ptr %t53 + %t55 = getelementptr inbounds ptr, ptr %t54, i32 0 + %t56 = load ptr, ptr %t55 + %t57 = call ptr @fn_emit_expr(ptr %t56) + store ptr %t57, ptr %t58 + %t59 = load ptr, ptr %t1 + %t60 = getelementptr inbounds %Str_Node, ptr %t59, i32 0, i32 7 + %t61 = load ptr, ptr %t60 + %t62 = getelementptr inbounds %LSlice, ptr %t61, i32 0, i32 0 + %t63 = load ptr, ptr %t62 + %t64 = getelementptr inbounds ptr, ptr %t63, i32 1 + %t65 = load ptr, ptr %t64 + %t66 = call ptr @fn_emit_expr(ptr %t65) + store ptr %t66, ptr %t67 + store ptr @.str618, ptr %t68 + %t69 = load ptr, ptr %t0 + %t70 = call i32 @fn_streq(ptr %t69, ptr @.str619) + %t71 = icmp ne i32 %t70, 0 + br i1 %t71, label %then8, label %ifend10 +then8: + store ptr @.str620, ptr %t68 + br label %ifend10 +ifend10: + %t72 = load ptr, ptr %t68 + %t73 = load ptr, ptr %t58 + %t74 = getelementptr inbounds %Str_Val, ptr %t73, i32 0, i32 0 + %t75 = load ptr, ptr %t74 + %t76 = load ptr, ptr %t67 + %t77 = getelementptr inbounds %Str_Val, ptr %t76, i32 0, i32 0 + %t78 = load ptr, ptr %t77 + %t79 = call ptr @fn_sconcat(ptr @.str623, ptr %t78) + %t80 = call ptr @fn_sconcat(ptr %t75, ptr %t79) + %t81 = call ptr @fn_sconcat(ptr @.str622, ptr %t80) + %t82 = call ptr @fn_sconcat(ptr %t72, ptr %t81) + %t83 = call ptr @fn_sconcat(ptr @.str621, ptr %t82) + %t84 = call ptr @fn_emit_bind(ptr %t83) + store ptr %t84, ptr %t85 + %t86 = load ptr, ptr %t85 + %t87 = load ptr, ptr %t58 + %t88 = getelementptr inbounds %Str_Val, ptr %t87, i32 0, i32 0 + %t89 = load ptr, ptr %t88 + %t90 = load ptr, ptr %t67 + %t91 = getelementptr inbounds %Str_Val, ptr %t90, i32 0, i32 0 + %t92 = load ptr, ptr %t91 + %t93 = call ptr @fn_sconcat(ptr @.str626, ptr %t92) + %t94 = call ptr @fn_sconcat(ptr %t89, ptr %t93) + %t95 = call ptr @fn_sconcat(ptr @.str625, ptr %t94) + %t96 = call ptr @fn_sconcat(ptr %t86, ptr %t95) + %t97 = call ptr @fn_sconcat(ptr @.str624, ptr %t96) + %t98 = call ptr @fn_emit_bind(ptr %t97) + %t99 = call ptr @fn_val(ptr %t98, ptr @.str627) + store ptr %t99, ptr %retval + br label %ret +ifend7: + %t100 = load ptr, ptr %t1 + %t101 = getelementptr inbounds %Str_Node, ptr %t100, i32 0, i32 7 + %t102 = load ptr, ptr %t101 + %t103 = getelementptr inbounds %LSlice, ptr %t102, i32 0, i32 0 + %t104 = load ptr, ptr %t103 + %t105 = getelementptr inbounds ptr, ptr %t104, i32 0 + %t106 = load ptr, ptr %t105 + %t107 = call ptr @fn_emit_expr(ptr %t106) + store ptr %t107, ptr %t108 + %t109 = load ptr, ptr %t1 + %t110 = getelementptr inbounds %Str_Node, ptr %t109, i32 0, i32 7 + %t111 = load ptr, ptr %t110 + %t112 = getelementptr inbounds %LSlice, ptr %t111, i32 0, i32 0 + %t113 = load ptr, ptr %t112 + %t114 = getelementptr inbounds ptr, ptr %t113, i32 1 + %t115 = load ptr, ptr %t114 + %t116 = call ptr @fn_emit_expr(ptr %t115) + store ptr %t116, ptr %t117 + %t118 = load ptr, ptr %t1 + %t119 = getelementptr inbounds %Str_Node, ptr %t118, i32 0, i32 7 + %t120 = load ptr, ptr %t119 + %t121 = getelementptr inbounds %LSlice, ptr %t120, i32 0, i32 0 + %t122 = load ptr, ptr %t121 + %t123 = getelementptr inbounds ptr, ptr %t122, i32 2 + %t124 = load ptr, ptr %t123 + %t125 = call ptr @fn_emit_expr(ptr %t124) + store ptr %t125, ptr %t126 + %t127 = load ptr, ptr %t108 + %t128 = getelementptr inbounds %Str_Val, ptr %t127, i32 0, i32 0 + %t129 = load ptr, ptr %t128 + %t130 = load ptr, ptr %t126 + %t131 = getelementptr inbounds %Str_Val, ptr %t130, i32 0, i32 0 + %t132 = load ptr, ptr %t131 + %t133 = call ptr @fn_sconcat(ptr @.str629, ptr %t132) + %t134 = call ptr @fn_sconcat(ptr %t129, ptr %t133) + %t135 = call ptr @fn_sconcat(ptr @.str628, ptr %t134) + %t136 = call ptr @fn_emit_bind(ptr %t135) + store ptr %t136, ptr %t137 + %t138 = load ptr, ptr %t137 + %t139 = load ptr, ptr %t108 + %t140 = getelementptr inbounds %Str_Val, ptr %t139, i32 0, i32 0 + %t141 = load ptr, ptr %t140 + %t142 = load ptr, ptr %t126 + %t143 = getelementptr inbounds %Str_Val, ptr %t142, i32 0, i32 0 + %t144 = load ptr, ptr %t143 + %t145 = call ptr @fn_sconcat(ptr @.str632, ptr %t144) + %t146 = call ptr @fn_sconcat(ptr %t141, ptr %t145) + %t147 = call ptr @fn_sconcat(ptr @.str631, ptr %t146) + %t148 = call ptr @fn_sconcat(ptr %t138, ptr %t147) + %t149 = call ptr @fn_sconcat(ptr @.str630, ptr %t148) + %t150 = call ptr @fn_emit_bind(ptr %t149) + store ptr %t150, ptr %t151 + %t152 = load ptr, ptr %t117 + %t153 = getelementptr inbounds %Str_Val, ptr %t152, i32 0, i32 0 + %t154 = load ptr, ptr %t153 + %t155 = load ptr, ptr %t151 + %t156 = call ptr @fn_sconcat(ptr @.str634, ptr %t155) + %t157 = call ptr @fn_sconcat(ptr %t154, ptr %t156) + %t158 = call ptr @fn_sconcat(ptr @.str633, ptr %t157) + %t159 = call ptr @fn_emit_bind(ptr %t158) + store ptr %t159, ptr %t160 + %t161 = load ptr, ptr %t160 + %t162 = load ptr, ptr %t117 + %t163 = getelementptr inbounds %Str_Val, ptr %t162, i32 0, i32 0 + %t164 = load ptr, ptr %t163 + %t165 = load ptr, ptr %t151 + %t166 = call ptr @fn_sconcat(ptr @.str637, ptr %t165) + %t167 = call ptr @fn_sconcat(ptr %t164, ptr %t166) + %t168 = call ptr @fn_sconcat(ptr @.str636, ptr %t167) + %t169 = call ptr @fn_sconcat(ptr %t161, ptr %t168) + %t170 = call ptr @fn_sconcat(ptr @.str635, ptr %t169) + %t171 = call ptr @fn_emit_bind(ptr %t170) + %t172 = call ptr @fn_val(ptr %t171, ptr @.str638) + store ptr %t172, ptr %retval + br label %ret +ret: + %t173 = load ptr, ptr %retval + ret ptr %t173 +} + +define ptr @fn_emit_sizeof(ptr %arg_llt) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t5 = alloca ptr + store ptr %arg_llt, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call ptr @fn_sconcat(ptr %t1, ptr @.str640) + %t3 = call ptr @fn_sconcat(ptr @.str639, ptr %t2) + %t4 = call ptr @fn_emit_bind(ptr %t3) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = call ptr @fn_sconcat(ptr %t6, ptr @.str642) + %t8 = call ptr @fn_sconcat(ptr @.str641, ptr %t7) + %t9 = call ptr @fn_emit_bind(ptr %t8) + store ptr %t9, ptr %retval + br label %ret +ret: + %t10 = load ptr, ptr %retval + ret ptr %t10 +} + +define ptr @fn_emit_new_struct(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t3 = alloca ptr + %t11 = alloca ptr + %t16 = alloca ptr + %t17 = alloca i32 + %t35 = alloca ptr + %t37 = alloca ptr + %t47 = alloca ptr + %t48 = alloca ptr + %t64 = alloca ptr + store ptr %arg_name, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call ptr @fn_find_struct(ptr %t1) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr %t3 + %t5 = icmp eq ptr %t4, null + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + call void @fn_perr(ptr @.str643) + br label %ifend2 +ifend2: + %t8 = load ptr, ptr %t0 + %t9 = call ptr @fn_sconcat(ptr @.str644, ptr %t8) + %t10 = call ptr @fn_emit_sizeof(ptr %t9) + store ptr %t10, ptr %t11 + %t12 = load ptr, ptr %t11 + %t13 = call ptr @fn_sconcat(ptr %t12, ptr @.str646) + %t14 = call ptr @fn_sconcat(ptr @.str645, ptr %t13) + %t15 = call ptr @fn_emit_bind(ptr %t14) + store ptr %t15, ptr %t16 + store i32 0, ptr %t17 + br label %wcond3 +wcond3: + %t18 = load i32, ptr %t17 + %t19 = load ptr, ptr %t3 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 7 + %t21 = load ptr, ptr %t20 + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 1 + %t23 = load i32, ptr %t22 + %t24 = icmp slt i32 %t18, %t23 + %t25 = zext i1 %t24 to i32 + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %wbody4, label %wend5 +wbody4: + %t27 = load ptr, ptr %t3 + %t28 = getelementptr inbounds %Str_Node, ptr %t27, i32 0, i32 7 + %t29 = load ptr, ptr %t28 + %t30 = getelementptr inbounds %LSlice, ptr %t29, i32 0, i32 0 + %t31 = load ptr, ptr %t30 + %t32 = load i32, ptr %t17 + %t33 = getelementptr inbounds ptr, ptr %t31, i32 %t32 + %t34 = load ptr, ptr %t33 + store ptr %t34, ptr %t35 + %t36 = call ptr @fn_nreg() + store ptr %t36, ptr %t37 + call void @fn_emit(ptr @.str647) + %t38 = load ptr, ptr %t37 + call void @fn_emit(ptr %t38) + call void @fn_emit(ptr @.str648) + %t39 = load ptr, ptr %t0 + call void @fn_emit(ptr %t39) + call void @fn_emit(ptr @.str649) + %t40 = load ptr, ptr %t16 + call void @fn_emit(ptr %t40) + call void @fn_emit(ptr @.str650) + %t41 = load i32, ptr %t17 + %t42 = call ptr @fn_itoa(i32 %t41) + call void @fn_emit(ptr %t42) + call void @fn_emit(ptr @.str651) + %t43 = load ptr, ptr %t35 + %t44 = getelementptr inbounds %Str_Node, ptr %t43, i32 0, i32 3 + %t45 = load ptr, ptr %t44 + %t46 = call ptr @fn_llty(ptr %t45) + store ptr %t46, ptr %t47 + store ptr @.str652, ptr %t48 + %t49 = load ptr, ptr %t47 + %t50 = call i32 @fn_streq(ptr %t49, ptr @.str653) + %t51 = icmp ne i32 %t50, 0 + br i1 %t51, label %then6, label %ifend8 +then6: + store ptr @.str654, ptr %t48 + br label %ifend8 +ifend8: + %t52 = load ptr, ptr %t35 + %t53 = getelementptr inbounds %Str_Node, ptr %t52, i32 0, i32 4 + %t54 = load ptr, ptr %t53 + %t55 = icmp eq ptr %t54, null + %t56 = zext i1 %t55 to i32 + %t57 = icmp eq i32 %t56, 0 + %t58 = zext i1 %t57 to i32 + %t59 = icmp ne i32 %t58, 0 + br i1 %t59, label %then9, label %ifend11 +then9: + %t60 = load ptr, ptr %t35 + %t61 = getelementptr inbounds %Str_Node, ptr %t60, i32 0, i32 4 + %t62 = load ptr, ptr %t61 + %t63 = call ptr @fn_emit_expr(ptr %t62) + store ptr %t63, ptr %t64 + %t65 = load ptr, ptr %t64 + %t66 = getelementptr inbounds %Str_Val, ptr %t65, i32 0, i32 0 + %t67 = load ptr, ptr %t66 + store ptr %t67, ptr %t48 + br label %ifend11 +ifend11: + call void @fn_emit(ptr @.str655) + %t68 = load ptr, ptr %t47 + call void @fn_emit(ptr %t68) + call void @fn_emit(ptr @.str656) + %t69 = load ptr, ptr %t48 + call void @fn_emit(ptr %t69) + call void @fn_emit(ptr @.str657) + %t70 = load ptr, ptr %t37 + call void @fn_emit(ptr %t70) + call void @fn_emit(ptr @.str658) + %t71 = load i32, ptr %t17 + %t72 = add i32 %t71, 1 + store i32 %t72, ptr %t17 + br label %wcond3 +wend5: + %t73 = load ptr, ptr %t16 + %t74 = load ptr, ptr %t0 + %t75 = call ptr @fn_val(ptr %t73, ptr %t74) + store ptr %t75, ptr %retval + br label %ret +ret: + %t76 = load ptr, ptr %retval + ret ptr %t76 +} + +define ptr @fn_emit_new_slice(ptr %arg_ty) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t2 = alloca ptr + %t7 = alloca ptr + %t9 = alloca ptr + %t14 = alloca ptr + %t19 = alloca ptr + store ptr %arg_ty, ptr %t0 + %t1 = call ptr @fn_emit_sizeof(ptr @.str659) + store ptr %t1, ptr %t2 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_sconcat(ptr %t3, ptr @.str661) + %t5 = call ptr @fn_sconcat(ptr @.str660, ptr %t4) + %t6 = call ptr @fn_emit_bind(ptr %t5) + store ptr %t6, ptr %t7 + %t8 = call ptr @fn_nreg() + store ptr %t8, ptr %t9 + call void @fn_emit(ptr @.str662) + %t10 = load ptr, ptr %t9 + call void @fn_emit(ptr %t10) + call void @fn_emit(ptr @.str663) + %t11 = load ptr, ptr %t7 + call void @fn_emit(ptr %t11) + call void @fn_emit(ptr @.str664) + call void @fn_emit(ptr @.str665) + %t12 = load ptr, ptr %t9 + call void @fn_emit(ptr %t12) + call void @fn_emit(ptr @.str666) + %t13 = call ptr @fn_nreg() + store ptr %t13, ptr %t14 + call void @fn_emit(ptr @.str667) + %t15 = load ptr, ptr %t14 + call void @fn_emit(ptr %t15) + call void @fn_emit(ptr @.str668) + %t16 = load ptr, ptr %t7 + call void @fn_emit(ptr %t16) + call void @fn_emit(ptr @.str669) + call void @fn_emit(ptr @.str670) + %t17 = load ptr, ptr %t14 + call void @fn_emit(ptr %t17) + call void @fn_emit(ptr @.str671) + %t18 = call ptr @fn_nreg() + store ptr %t18, ptr %t19 + call void @fn_emit(ptr @.str672) + %t20 = load ptr, ptr %t19 + call void @fn_emit(ptr %t20) + call void @fn_emit(ptr @.str673) + %t21 = load ptr, ptr %t7 + call void @fn_emit(ptr %t21) + call void @fn_emit(ptr @.str674) + call void @fn_emit(ptr @.str675) + %t22 = load ptr, ptr %t19 + call void @fn_emit(ptr %t22) + call void @fn_emit(ptr @.str676) + %t23 = load ptr, ptr %t7 + %t24 = load ptr, ptr %t0 + %t25 = call ptr @fn_val(ptr %t23, ptr %t24) + store ptr %t25, ptr %retval + br label %ret +ret: + %t26 = load ptr, ptr %retval + ret ptr %t26 +} + +define ptr @fn_slice_field(ptr %arg_h, i32 %arg_i) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t3 = alloca ptr + store ptr %arg_h, ptr %t0 + store i32 %arg_i, ptr %t1 + %t2 = call ptr @fn_nreg() + store ptr %t2, ptr %t3 + call void @fn_emit(ptr @.str677) + %t4 = load ptr, ptr %t3 + call void @fn_emit(ptr %t4) + call void @fn_emit(ptr @.str678) + %t5 = load ptr, ptr %t0 + call void @fn_emit(ptr %t5) + call void @fn_emit(ptr @.str679) + %t6 = load i32, ptr %t1 + %t7 = call ptr @fn_itoa(i32 %t6) + call void @fn_emit(ptr %t7) + call void @fn_emit(ptr @.str680) + %t8 = load ptr, ptr %t3 + store ptr %t8, ptr %retval + br label %ret +ret: + %t9 = load ptr, ptr %retval + ret ptr %t9 +} + +define ptr @fn_emit_len(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t9 = alloca ptr + %t14 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 7 + %t3 = load ptr, ptr %t2 + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 0 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds ptr, ptr %t5, i32 0 + %t7 = load ptr, ptr %t6 + %t8 = call ptr @fn_emit_expr(ptr %t7) + store ptr %t8, ptr %t9 + %t10 = load ptr, ptr %t9 + %t11 = getelementptr inbounds %Str_Val, ptr %t10, i32 0, i32 0 + %t12 = load ptr, ptr %t11 + %t13 = call ptr @fn_slice_field(ptr %t12, i32 1) + store ptr %t13, ptr %t14 + %t15 = load ptr, ptr %t14 + %t16 = call ptr @fn_sconcat(ptr @.str681, ptr %t15) + %t17 = call ptr @fn_emit_bind(ptr %t16) + %t18 = call ptr @fn_val(ptr %t17, ptr @.str682) + store ptr %t18, ptr %retval + br label %ret +ret: + %t19 = load ptr, ptr %retval + ret ptr %t19 +} + +define ptr @fn_emit_push(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t9 = alloca ptr + %t14 = alloca ptr + %t17 = alloca ptr + %t21 = alloca ptr + %t24 = alloca ptr + %t27 = alloca ptr + %t30 = alloca ptr + %t34 = alloca ptr + %t38 = alloca ptr + %t45 = alloca ptr + %t47 = alloca ptr + %t49 = alloca ptr + %t58 = alloca ptr + %t63 = alloca ptr + %t70 = alloca ptr + %t73 = alloca ptr + %t78 = alloca ptr + %t85 = alloca ptr + %t89 = alloca ptr + %t97 = alloca ptr + %t112 = alloca ptr + %t116 = alloca ptr + %t118 = alloca ptr + %t132 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 7 + %t3 = load ptr, ptr %t2 + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 0 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds ptr, ptr %t5, i32 0 + %t7 = load ptr, ptr %t6 + %t8 = call ptr @fn_emit_expr(ptr %t7) + store ptr %t8, ptr %t9 + %t10 = load ptr, ptr %t9 + %t11 = getelementptr inbounds %Str_Val, ptr %t10, i32 0, i32 1 + %t12 = load ptr, ptr %t11 + %t13 = call ptr @fn_slice_elem(ptr %t12) + store ptr %t13, ptr %t14 + %t15 = load ptr, ptr %t14 + %t16 = call ptr @fn_llty(ptr %t15) + store ptr %t16, ptr %t17 + %t18 = load ptr, ptr %t9 + %t19 = getelementptr inbounds %Str_Val, ptr %t18, i32 0, i32 0 + %t20 = load ptr, ptr %t19 + store ptr %t20, ptr %t21 + %t22 = load ptr, ptr %t21 + %t23 = call ptr @fn_slice_field(ptr %t22, i32 1) + store ptr %t23, ptr %t24 + %t25 = load ptr, ptr %t21 + %t26 = call ptr @fn_slice_field(ptr %t25, i32 2) + store ptr %t26, ptr %t27 + %t28 = load ptr, ptr %t21 + %t29 = call ptr @fn_slice_field(ptr %t28, i32 0) + store ptr %t29, ptr %t30 + %t31 = load ptr, ptr %t24 + %t32 = call ptr @fn_sconcat(ptr @.str683, ptr %t31) + %t33 = call ptr @fn_emit_bind(ptr %t32) + store ptr %t33, ptr %t34 + %t35 = load ptr, ptr %t27 + %t36 = call ptr @fn_sconcat(ptr @.str684, ptr %t35) + %t37 = call ptr @fn_emit_bind(ptr %t36) + store ptr %t37, ptr %t38 + %t39 = load ptr, ptr %t34 + %t40 = load ptr, ptr %t38 + %t41 = call ptr @fn_sconcat(ptr @.str686, ptr %t40) + %t42 = call ptr @fn_sconcat(ptr %t39, ptr %t41) + %t43 = call ptr @fn_sconcat(ptr @.str685, ptr %t42) + %t44 = call ptr @fn_emit_bind(ptr %t43) + store ptr %t44, ptr %t45 + %t46 = call ptr @fn_lbl(ptr @.str687) + store ptr %t46, ptr %t47 + %t48 = call ptr @fn_lbl(ptr @.str688) + store ptr %t48, ptr %t49 + call void @fn_emit(ptr @.str689) + %t50 = load ptr, ptr %t45 + call void @fn_emit(ptr %t50) + call void @fn_emit(ptr @.str690) + %t51 = load ptr, ptr %t47 + call void @fn_emit(ptr %t51) + call void @fn_emit(ptr @.str691) + %t52 = load ptr, ptr %t49 + call void @fn_emit(ptr %t52) + call void @fn_emit(ptr @.str692) + %t53 = load ptr, ptr %t47 + call void @fn_emit(ptr %t53) + call void @fn_emit(ptr @.str693) + %t54 = load ptr, ptr %t38 + %t55 = call ptr @fn_sconcat(ptr %t54, ptr @.str695) + %t56 = call ptr @fn_sconcat(ptr @.str694, ptr %t55) + %t57 = call ptr @fn_emit_bind(ptr %t56) + store ptr %t57, ptr %t58 + %t59 = load ptr, ptr %t38 + %t60 = call ptr @fn_sconcat(ptr %t59, ptr @.str697) + %t61 = call ptr @fn_sconcat(ptr @.str696, ptr %t60) + %t62 = call ptr @fn_emit_bind(ptr %t61) + store ptr %t62, ptr %t63 + %t64 = load ptr, ptr %t63 + %t65 = load ptr, ptr %t58 + %t66 = call ptr @fn_sconcat(ptr @.str699, ptr %t65) + %t67 = call ptr @fn_sconcat(ptr %t64, ptr %t66) + %t68 = call ptr @fn_sconcat(ptr @.str698, ptr %t67) + %t69 = call ptr @fn_emit_bind(ptr %t68) + store ptr %t69, ptr %t70 + %t71 = load ptr, ptr %t17 + %t72 = call ptr @fn_emit_sizeof(ptr %t71) + store ptr %t72, ptr %t73 + %t74 = load ptr, ptr %t70 + %t75 = call ptr @fn_sconcat(ptr %t74, ptr @.str701) + %t76 = call ptr @fn_sconcat(ptr @.str700, ptr %t75) + %t77 = call ptr @fn_emit_bind(ptr %t76) + store ptr %t77, ptr %t78 + %t79 = load ptr, ptr %t78 + %t80 = load ptr, ptr %t73 + %t81 = call ptr @fn_sconcat(ptr @.str703, ptr %t80) + %t82 = call ptr @fn_sconcat(ptr %t79, ptr %t81) + %t83 = call ptr @fn_sconcat(ptr @.str702, ptr %t82) + %t84 = call ptr @fn_emit_bind(ptr %t83) + store ptr %t84, ptr %t85 + %t86 = load ptr, ptr %t30 + %t87 = call ptr @fn_sconcat(ptr @.str704, ptr %t86) + %t88 = call ptr @fn_emit_bind(ptr %t87) + store ptr %t88, ptr %t89 + %t90 = load ptr, ptr %t89 + %t91 = load ptr, ptr %t85 + %t92 = call ptr @fn_sconcat(ptr %t91, ptr @.str707) + %t93 = call ptr @fn_sconcat(ptr @.str706, ptr %t92) + %t94 = call ptr @fn_sconcat(ptr %t90, ptr %t93) + %t95 = call ptr @fn_sconcat(ptr @.str705, ptr %t94) + %t96 = call ptr @fn_emit_bind(ptr %t95) + store ptr %t96, ptr %t97 + call void @fn_emit(ptr @.str708) + %t98 = load ptr, ptr %t97 + call void @fn_emit(ptr %t98) + call void @fn_emit(ptr @.str709) + %t99 = load ptr, ptr %t30 + call void @fn_emit(ptr %t99) + call void @fn_emit(ptr @.str710) + call void @fn_emit(ptr @.str711) + %t100 = load ptr, ptr %t70 + call void @fn_emit(ptr %t100) + call void @fn_emit(ptr @.str712) + %t101 = load ptr, ptr %t27 + call void @fn_emit(ptr %t101) + call void @fn_emit(ptr @.str713) + call void @fn_emit(ptr @.str714) + %t102 = load ptr, ptr %t49 + call void @fn_emit(ptr %t102) + call void @fn_emit(ptr @.str715) + %t103 = load ptr, ptr %t49 + call void @fn_emit(ptr %t103) + call void @fn_emit(ptr @.str716) + %t104 = load ptr, ptr %t0 + %t105 = getelementptr inbounds %Str_Node, ptr %t104, i32 0, i32 7 + %t106 = load ptr, ptr %t105 + %t107 = getelementptr inbounds %LSlice, ptr %t106, i32 0, i32 0 + %t108 = load ptr, ptr %t107 + %t109 = getelementptr inbounds ptr, ptr %t108, i32 1 + %t110 = load ptr, ptr %t109 + %t111 = call ptr @fn_emit_expr(ptr %t110) + store ptr %t111, ptr %t112 + %t113 = load ptr, ptr %t30 + %t114 = call ptr @fn_sconcat(ptr @.str717, ptr %t113) + %t115 = call ptr @fn_emit_bind(ptr %t114) + store ptr %t115, ptr %t116 + %t117 = call ptr @fn_nreg() + store ptr %t117, ptr %t118 + call void @fn_emit(ptr @.str718) + %t119 = load ptr, ptr %t118 + call void @fn_emit(ptr %t119) + call void @fn_emit(ptr @.str719) + %t120 = load ptr, ptr %t17 + call void @fn_emit(ptr %t120) + call void @fn_emit(ptr @.str720) + %t121 = load ptr, ptr %t116 + call void @fn_emit(ptr %t121) + call void @fn_emit(ptr @.str721) + %t122 = load ptr, ptr %t34 + call void @fn_emit(ptr %t122) + call void @fn_emit(ptr @.str722) + call void @fn_emit(ptr @.str723) + %t123 = load ptr, ptr %t17 + call void @fn_emit(ptr %t123) + call void @fn_emit(ptr @.str724) + %t124 = load ptr, ptr %t112 + %t125 = getelementptr inbounds %Str_Val, ptr %t124, i32 0, i32 0 + %t126 = load ptr, ptr %t125 + call void @fn_emit(ptr %t126) + call void @fn_emit(ptr @.str725) + %t127 = load ptr, ptr %t118 + call void @fn_emit(ptr %t127) + call void @fn_emit(ptr @.str726) + %t128 = load ptr, ptr %t34 + %t129 = call ptr @fn_sconcat(ptr %t128, ptr @.str728) + %t130 = call ptr @fn_sconcat(ptr @.str727, ptr %t129) + %t131 = call ptr @fn_emit_bind(ptr %t130) + store ptr %t131, ptr %t132 + call void @fn_emit(ptr @.str729) + %t133 = load ptr, ptr %t132 + call void @fn_emit(ptr %t133) + call void @fn_emit(ptr @.str730) + %t134 = load ptr, ptr %t24 + call void @fn_emit(ptr %t134) + call void @fn_emit(ptr @.str731) + %t135 = call ptr @fn_val(ptr @.str732, ptr @.str733) + store ptr %t135, ptr %retval + br label %ret +ret: + %t136 = load ptr, ptr %retval + ret ptr %t136 +} + +define ptr @fn_emit_load_at(ptr %arg_addr, ptr %arg_ty) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t9 = alloca ptr + store ptr %arg_addr, ptr %t0 + store ptr %arg_ty, ptr %t1 + %t2 = load ptr, ptr %t1 + %t3 = call ptr @fn_llty(ptr %t2) + %t4 = load ptr, ptr %t0 + %t5 = call ptr @fn_sconcat(ptr @.str735, ptr %t4) + %t6 = call ptr @fn_sconcat(ptr %t3, ptr %t5) + %t7 = call ptr @fn_sconcat(ptr @.str734, ptr %t6) + %t8 = call ptr @fn_emit_bind(ptr %t7) + store ptr %t8, ptr %t9 + %t10 = load ptr, ptr %t9 + %t11 = load ptr, ptr %t1 + %t12 = call ptr @fn_val(ptr %t10, ptr %t11) + store ptr %t12, ptr %retval + br label %ret +ret: + %t13 = load ptr, ptr %retval + ret ptr %t13 +} + +define ptr @fn_emit_logic(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t2 = alloca ptr + %t7 = alloca ptr + %t14 = alloca ptr + %t19 = alloca ptr + %t23 = alloca ptr + %t25 = alloca ptr + %t42 = alloca ptr + %t49 = alloca ptr + %t54 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = call ptr @fn_emit_alloca(ptr @.str736) + store ptr %t1, ptr %t2 + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 4 + %t5 = load ptr, ptr %t4 + %t6 = call ptr @fn_emit_expr(ptr %t5) + store ptr %t6, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds %Str_Val, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t9 + %t11 = call ptr @fn_sconcat(ptr %t10, ptr @.str738) + %t12 = call ptr @fn_sconcat(ptr @.str737, ptr %t11) + %t13 = call ptr @fn_emit_bind(ptr %t12) + store ptr %t13, ptr %t14 + %t15 = load ptr, ptr %t14 + %t16 = call ptr @fn_sconcat(ptr %t15, ptr @.str740) + %t17 = call ptr @fn_sconcat(ptr @.str739, ptr %t16) + %t18 = call ptr @fn_emit_bind(ptr %t17) + store ptr %t18, ptr %t19 + call void @fn_emit(ptr @.str741) + %t20 = load ptr, ptr %t19 + call void @fn_emit(ptr %t20) + call void @fn_emit(ptr @.str742) + %t21 = load ptr, ptr %t2 + call void @fn_emit(ptr %t21) + call void @fn_emit(ptr @.str743) + %t22 = call ptr @fn_lbl(ptr @.str744) + store ptr %t22, ptr %t23 + %t24 = call ptr @fn_lbl(ptr @.str745) + store ptr %t24, ptr %t25 + %t26 = load ptr, ptr %t0 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 1 + %t28 = load ptr, ptr %t27 + %t29 = call i32 @fn_streq(ptr %t28, ptr @.str746) + %t30 = icmp ne i32 %t29, 0 + br i1 %t30, label %then0, label %else1 +then0: + call void @fn_emit(ptr @.str747) + %t31 = load ptr, ptr %t14 + call void @fn_emit(ptr %t31) + call void @fn_emit(ptr @.str748) + %t32 = load ptr, ptr %t23 + call void @fn_emit(ptr %t32) + call void @fn_emit(ptr @.str749) + %t33 = load ptr, ptr %t25 + call void @fn_emit(ptr %t33) + call void @fn_emit(ptr @.str750) + br label %ifend2 +else1: + call void @fn_emit(ptr @.str751) + %t34 = load ptr, ptr %t14 + call void @fn_emit(ptr %t34) + call void @fn_emit(ptr @.str752) + %t35 = load ptr, ptr %t25 + call void @fn_emit(ptr %t35) + call void @fn_emit(ptr @.str753) + %t36 = load ptr, ptr %t23 + call void @fn_emit(ptr %t36) + call void @fn_emit(ptr @.str754) + br label %ifend2 +ifend2: + %t37 = load ptr, ptr %t23 + call void @fn_emit(ptr %t37) + call void @fn_emit(ptr @.str755) + %t38 = load ptr, ptr %t0 + %t39 = getelementptr inbounds %Str_Node, ptr %t38, i32 0, i32 5 + %t40 = load ptr, ptr %t39 + %t41 = call ptr @fn_emit_expr(ptr %t40) + store ptr %t41, ptr %t42 + %t43 = load ptr, ptr %t42 + %t44 = getelementptr inbounds %Str_Val, ptr %t43, i32 0, i32 0 + %t45 = load ptr, ptr %t44 + %t46 = call ptr @fn_sconcat(ptr %t45, ptr @.str757) + %t47 = call ptr @fn_sconcat(ptr @.str756, ptr %t46) + %t48 = call ptr @fn_emit_bind(ptr %t47) + store ptr %t48, ptr %t49 + %t50 = load ptr, ptr %t49 + %t51 = call ptr @fn_sconcat(ptr %t50, ptr @.str759) + %t52 = call ptr @fn_sconcat(ptr @.str758, ptr %t51) + %t53 = call ptr @fn_emit_bind(ptr %t52) + store ptr %t53, ptr %t54 + call void @fn_emit(ptr @.str760) + %t55 = load ptr, ptr %t54 + call void @fn_emit(ptr %t55) + call void @fn_emit(ptr @.str761) + %t56 = load ptr, ptr %t2 + call void @fn_emit(ptr %t56) + call void @fn_emit(ptr @.str762) + call void @fn_emit(ptr @.str763) + %t57 = load ptr, ptr %t25 + call void @fn_emit(ptr %t57) + call void @fn_emit(ptr @.str764) + %t58 = load ptr, ptr %t25 + call void @fn_emit(ptr %t58) + call void @fn_emit(ptr @.str765) + %t59 = load ptr, ptr %t2 + %t60 = call ptr @fn_sconcat(ptr @.str766, ptr %t59) + %t61 = call ptr @fn_emit_bind(ptr %t60) + %t62 = call ptr @fn_val(ptr %t61, ptr @.str767) + store ptr %t62, ptr %retval + br label %ret +ret: + %t63 = load ptr, ptr %retval + ret ptr %t63 +} + +define ptr @fn_cmp_code(ptr %arg_op) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + store ptr %arg_op, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_streq(ptr %t1, ptr @.str768) + %t3 = icmp ne i32 %t2, 0 + br i1 %t3, label %then0, label %ifend2 +then0: + store ptr @.str769, ptr %retval + br label %ret +ifend2: + %t4 = load ptr, ptr %t0 + %t5 = call i32 @fn_streq(ptr %t4, ptr @.str770) + %t6 = icmp ne i32 %t5, 0 + br i1 %t6, label %then3, label %ifend5 +then3: + store ptr @.str771, ptr %retval + br label %ret +ifend5: + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str772) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then6, label %ifend8 +then6: + store ptr @.str773, ptr %retval + br label %ret +ifend8: + %t10 = load ptr, ptr %t0 + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str774) + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then9, label %ifend11 +then9: + store ptr @.str775, ptr %retval + br label %ret +ifend11: + %t13 = load ptr, ptr %t0 + %t14 = call i32 @fn_streq(ptr %t13, ptr @.str776) + %t15 = icmp ne i32 %t14, 0 + br i1 %t15, label %then12, label %ifend14 +then12: + store ptr @.str777, ptr %retval + br label %ret +ifend14: + store ptr @.str778, ptr %retval + br label %ret +ret: + %t16 = load ptr, ptr %retval + ret ptr %t16 +} + +define i32 @fn_is_cmp(ptr %arg_op) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t3 = alloca i32 + %t4 = alloca i32 + %t5 = alloca i32 + store ptr %arg_op, ptr %t0 + %t6 = load ptr, ptr %t0 + %t7 = call i32 @fn_streq(ptr %t6, ptr @.str779) + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t5 + br i1 %t8, label %scend1, label %sc0 +sc0: + %t10 = load ptr, ptr %t0 + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str780) + %t12 = icmp ne i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + store i32 %t13, ptr %t5 + br label %scend1 +scend1: + %t14 = load i32, ptr %t5 + %t15 = icmp ne i32 %t14, 0 + %t16 = zext i1 %t15 to i32 + store i32 %t16, ptr %t4 + br i1 %t15, label %scend3, label %sc2 +sc2: + %t17 = load ptr, ptr %t0 + %t18 = call i32 @fn_streq(ptr %t17, ptr @.str781) + %t19 = icmp ne i32 %t18, 0 + %t20 = zext i1 %t19 to i32 + store i32 %t20, ptr %t4 + br label %scend3 +scend3: + %t21 = load i32, ptr %t4 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t3 + br i1 %t22, label %scend5, label %sc4 +sc4: + %t24 = load ptr, ptr %t0 + %t25 = call i32 @fn_streq(ptr %t24, ptr @.str782) + %t26 = icmp ne i32 %t25, 0 + %t27 = zext i1 %t26 to i32 + store i32 %t27, ptr %t3 + br label %scend5 +scend5: + %t28 = load i32, ptr %t3 + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t2 + br i1 %t29, label %scend7, label %sc6 +sc6: + %t31 = load ptr, ptr %t0 + %t32 = call i32 @fn_streq(ptr %t31, ptr @.str783) + %t33 = icmp ne i32 %t32, 0 + %t34 = zext i1 %t33 to i32 + store i32 %t34, ptr %t2 + br label %scend7 +scend7: + %t35 = load i32, ptr %t2 + %t36 = icmp ne i32 %t35, 0 + %t37 = zext i1 %t36 to i32 + store i32 %t37, ptr %t1 + br i1 %t36, label %scend9, label %sc8 +sc8: + %t38 = load ptr, ptr %t0 + %t39 = call i32 @fn_streq(ptr %t38, ptr @.str784) + %t40 = icmp ne i32 %t39, 0 + %t41 = zext i1 %t40 to i32 + store i32 %t41, ptr %t1 + br label %scend9 +scend9: + %t42 = load i32, ptr %t1 + store i32 %t42, ptr %retval + br label %ret +ret: + %t43 = load i32, ptr %retval + ret i32 %t43 +} + +define ptr @fn_arith_code(ptr %arg_op) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + store ptr %arg_op, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_streq(ptr %t1, ptr @.str785) + %t3 = icmp ne i32 %t2, 0 + br i1 %t3, label %then0, label %ifend2 +then0: + store ptr @.str786, ptr %retval + br label %ret +ifend2: + %t4 = load ptr, ptr %t0 + %t5 = call i32 @fn_streq(ptr %t4, ptr @.str787) + %t6 = icmp ne i32 %t5, 0 + br i1 %t6, label %then3, label %ifend5 +then3: + store ptr @.str788, ptr %retval + br label %ret +ifend5: + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str789) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then6, label %ifend8 +then6: + store ptr @.str790, ptr %retval + br label %ret +ifend8: + %t10 = load ptr, ptr %t0 + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str791) + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then9, label %ifend11 +then9: + store ptr @.str792, ptr %retval + br label %ret +ifend11: + store ptr @.str793, ptr %retval + br label %ret +ret: + %t13 = load ptr, ptr %retval + ret ptr %t13 +} + +define ptr @fn_to_fixed(ptr %arg_v) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + store ptr %arg_v, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Val, ptr %t1, i32 0, i32 1 + %t3 = load ptr, ptr %t2 + %t4 = call i32 @fn_streq(ptr %t3, ptr @.str794) + %t5 = icmp ne i32 %t4, 0 + br i1 %t5, label %then0, label %ifend2 +then0: + %t6 = load ptr, ptr %t0 + %t7 = getelementptr inbounds %Str_Val, ptr %t6, i32 0, i32 0 + %t8 = load ptr, ptr %t7 + store ptr %t8, ptr %retval + br label %ret +ifend2: + %t9 = load ptr, ptr %t0 + %t10 = getelementptr inbounds %Str_Val, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = call ptr @fn_sconcat(ptr %t11, ptr @.str796) + %t13 = call ptr @fn_sconcat(ptr @.str795, ptr %t12) + %t14 = call ptr @fn_emit_bind(ptr %t13) + store ptr %t14, ptr %retval + br label %ret +ret: + %t15 = load ptr, ptr %retval + ret ptr %t15 +} + +define ptr @fn_emit_bin(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca i32 + %t22 = alloca ptr + %t27 = alloca ptr + %t28 = alloca i32 + %t42 = alloca i32 + %t51 = alloca ptr + %t55 = alloca ptr + %t74 = alloca ptr + %t84 = alloca ptr + %t87 = alloca ptr + %t97 = alloca ptr + %t102 = alloca ptr + %t109 = alloca ptr + %t114 = alloca ptr + %t129 = alloca ptr + %t134 = alloca ptr + %t139 = alloca ptr + %t146 = alloca ptr + %t163 = alloca ptr + %t181 = alloca ptr + store ptr %arg_e, ptr %t0 + %t2 = load ptr, ptr %t0 + %t3 = getelementptr inbounds %Str_Node, ptr %t2, i32 0, i32 1 + %t4 = load ptr, ptr %t3 + %t5 = call i32 @fn_streq(ptr %t4, ptr @.str797) + %t6 = icmp ne i32 %t5, 0 + %t7 = zext i1 %t6 to i32 + store i32 %t7, ptr %t1 + br i1 %t6, label %scend1, label %sc0 +sc0: + %t8 = load ptr, ptr %t0 + %t9 = getelementptr inbounds %Str_Node, ptr %t8, i32 0, i32 1 + %t10 = load ptr, ptr %t9 + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str798) + %t12 = icmp ne i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + store i32 %t13, ptr %t1 + br label %scend1 +scend1: + %t14 = load i32, ptr %t1 + %t15 = icmp ne i32 %t14, 0 + br i1 %t15, label %then2, label %ifend4 +then2: + %t16 = load ptr, ptr %t0 + %t17 = call ptr @fn_emit_logic(ptr %t16) + store ptr %t17, ptr %retval + br label %ret +ifend4: + %t18 = load ptr, ptr %t0 + %t19 = getelementptr inbounds %Str_Node, ptr %t18, i32 0, i32 4 + %t20 = load ptr, ptr %t19 + %t21 = call ptr @fn_emit_expr(ptr %t20) + store ptr %t21, ptr %t22 + %t23 = load ptr, ptr %t0 + %t24 = getelementptr inbounds %Str_Node, ptr %t23, i32 0, i32 5 + %t25 = load ptr, ptr %t24 + %t26 = call ptr @fn_emit_expr(ptr %t25) + store ptr %t26, ptr %t27 + %t29 = load ptr, ptr %t22 + %t30 = getelementptr inbounds %Str_Val, ptr %t29, i32 0, i32 1 + %t31 = load ptr, ptr %t30 + %t32 = call i32 @fn_streq(ptr %t31, ptr @.str799) + %t33 = icmp ne i32 %t32, 0 + %t34 = zext i1 %t33 to i32 + store i32 %t34, ptr %t28 + br i1 %t33, label %scend6, label %sc5 +sc5: + %t35 = load ptr, ptr %t27 + %t36 = getelementptr inbounds %Str_Val, ptr %t35, i32 0, i32 1 + %t37 = load ptr, ptr %t36 + %t38 = call i32 @fn_streq(ptr %t37, ptr @.str800) + %t39 = icmp ne i32 %t38, 0 + %t40 = zext i1 %t39 to i32 + store i32 %t40, ptr %t28 + br label %scend6 +scend6: + %t41 = load i32, ptr %t28 + store i32 %t41, ptr %t42 + %t43 = load ptr, ptr %t0 + %t44 = getelementptr inbounds %Str_Node, ptr %t43, i32 0, i32 1 + %t45 = load ptr, ptr %t44 + %t46 = call i32 @fn_is_cmp(ptr %t45) + %t47 = icmp ne i32 %t46, 0 + br i1 %t47, label %then7, label %ifend9 +then7: + %t48 = load ptr, ptr %t22 + %t49 = getelementptr inbounds %Str_Val, ptr %t48, i32 0, i32 0 + %t50 = load ptr, ptr %t49 + store ptr %t50, ptr %t51 + %t52 = load ptr, ptr %t27 + %t53 = getelementptr inbounds %Str_Val, ptr %t52, i32 0, i32 0 + %t54 = load ptr, ptr %t53 + store ptr %t54, ptr %t55 + %t56 = load i32, ptr %t42 + %t57 = icmp ne i32 %t56, 0 + br i1 %t57, label %then10, label %ifend12 +then10: + %t58 = load ptr, ptr %t22 + %t59 = call ptr @fn_to_fixed(ptr %t58) + store ptr %t59, ptr %t51 + %t60 = load ptr, ptr %t27 + %t61 = call ptr @fn_to_fixed(ptr %t60) + store ptr %t61, ptr %t55 + br label %ifend12 +ifend12: + %t62 = load ptr, ptr %t0 + %t63 = getelementptr inbounds %Str_Node, ptr %t62, i32 0, i32 1 + %t64 = load ptr, ptr %t63 + %t65 = call ptr @fn_cmp_code(ptr %t64) + %t66 = load ptr, ptr %t51 + %t67 = load ptr, ptr %t55 + %t68 = call ptr @fn_sconcat(ptr @.str803, ptr %t67) + %t69 = call ptr @fn_sconcat(ptr %t66, ptr %t68) + %t70 = call ptr @fn_sconcat(ptr @.str802, ptr %t69) + %t71 = call ptr @fn_sconcat(ptr %t65, ptr %t70) + %t72 = call ptr @fn_sconcat(ptr @.str801, ptr %t71) + %t73 = call ptr @fn_emit_bind(ptr %t72) + store ptr %t73, ptr %t74 + %t75 = load ptr, ptr %t74 + %t76 = call ptr @fn_sconcat(ptr %t75, ptr @.str805) + %t77 = call ptr @fn_sconcat(ptr @.str804, ptr %t76) + %t78 = call ptr @fn_emit_bind(ptr %t77) + %t79 = call ptr @fn_val(ptr %t78, ptr @.str806) + store ptr %t79, ptr %retval + br label %ret +ifend9: + %t80 = load i32, ptr %t42 + %t81 = icmp ne i32 %t80, 0 + br i1 %t81, label %then13, label %ifend15 +then13: + %t82 = load ptr, ptr %t22 + %t83 = call ptr @fn_to_fixed(ptr %t82) + store ptr %t83, ptr %t84 + %t85 = load ptr, ptr %t27 + %t86 = call ptr @fn_to_fixed(ptr %t85) + store ptr %t86, ptr %t87 + %t88 = load ptr, ptr %t0 + %t89 = getelementptr inbounds %Str_Node, ptr %t88, i32 0, i32 1 + %t90 = load ptr, ptr %t89 + %t91 = call i32 @fn_streq(ptr %t90, ptr @.str807) + %t92 = icmp ne i32 %t91, 0 + br i1 %t92, label %then16, label %ifend18 +then16: + %t93 = load ptr, ptr %t84 + %t94 = call ptr @fn_sconcat(ptr %t93, ptr @.str809) + %t95 = call ptr @fn_sconcat(ptr @.str808, ptr %t94) + %t96 = call ptr @fn_emit_bind(ptr %t95) + store ptr %t96, ptr %t97 + %t98 = load ptr, ptr %t87 + %t99 = call ptr @fn_sconcat(ptr %t98, ptr @.str811) + %t100 = call ptr @fn_sconcat(ptr @.str810, ptr %t99) + %t101 = call ptr @fn_emit_bind(ptr %t100) + store ptr %t101, ptr %t102 + %t103 = load ptr, ptr %t97 + %t104 = load ptr, ptr %t102 + %t105 = call ptr @fn_sconcat(ptr @.str813, ptr %t104) + %t106 = call ptr @fn_sconcat(ptr %t103, ptr %t105) + %t107 = call ptr @fn_sconcat(ptr @.str812, ptr %t106) + %t108 = call ptr @fn_emit_bind(ptr %t107) + store ptr %t108, ptr %t109 + %t110 = load ptr, ptr %t109 + %t111 = call ptr @fn_sconcat(ptr %t110, ptr @.str815) + %t112 = call ptr @fn_sconcat(ptr @.str814, ptr %t111) + %t113 = call ptr @fn_emit_bind(ptr %t112) + store ptr %t113, ptr %t114 + %t115 = load ptr, ptr %t114 + %t116 = call ptr @fn_sconcat(ptr %t115, ptr @.str817) + %t117 = call ptr @fn_sconcat(ptr @.str816, ptr %t116) + %t118 = call ptr @fn_emit_bind(ptr %t117) + %t119 = call ptr @fn_val(ptr %t118, ptr @.str818) + store ptr %t119, ptr %retval + br label %ret +ifend18: + %t120 = load ptr, ptr %t0 + %t121 = getelementptr inbounds %Str_Node, ptr %t120, i32 0, i32 1 + %t122 = load ptr, ptr %t121 + %t123 = call i32 @fn_streq(ptr %t122, ptr @.str819) + %t124 = icmp ne i32 %t123, 0 + br i1 %t124, label %then19, label %ifend21 +then19: + %t125 = load ptr, ptr %t84 + %t126 = call ptr @fn_sconcat(ptr %t125, ptr @.str821) + %t127 = call ptr @fn_sconcat(ptr @.str820, ptr %t126) + %t128 = call ptr @fn_emit_bind(ptr %t127) + store ptr %t128, ptr %t129 + %t130 = load ptr, ptr %t129 + %t131 = call ptr @fn_sconcat(ptr %t130, ptr @.str823) + %t132 = call ptr @fn_sconcat(ptr @.str822, ptr %t131) + %t133 = call ptr @fn_emit_bind(ptr %t132) + store ptr %t133, ptr %t134 + %t135 = load ptr, ptr %t87 + %t136 = call ptr @fn_sconcat(ptr %t135, ptr @.str825) + %t137 = call ptr @fn_sconcat(ptr @.str824, ptr %t136) + %t138 = call ptr @fn_emit_bind(ptr %t137) + store ptr %t138, ptr %t139 + %t140 = load ptr, ptr %t134 + %t141 = load ptr, ptr %t139 + %t142 = call ptr @fn_sconcat(ptr @.str827, ptr %t141) + %t143 = call ptr @fn_sconcat(ptr %t140, ptr %t142) + %t144 = call ptr @fn_sconcat(ptr @.str826, ptr %t143) + %t145 = call ptr @fn_emit_bind(ptr %t144) + store ptr %t145, ptr %t146 + %t147 = load ptr, ptr %t146 + %t148 = call ptr @fn_sconcat(ptr %t147, ptr @.str829) + %t149 = call ptr @fn_sconcat(ptr @.str828, ptr %t148) + %t150 = call ptr @fn_emit_bind(ptr %t149) + %t151 = call ptr @fn_val(ptr %t150, ptr @.str830) + store ptr %t151, ptr %retval + br label %ret +ifend21: + %t152 = load ptr, ptr %t0 + %t153 = getelementptr inbounds %Str_Node, ptr %t152, i32 0, i32 1 + %t154 = load ptr, ptr %t153 + %t155 = call ptr @fn_arith_code(ptr %t154) + %t156 = load ptr, ptr %t84 + %t157 = load ptr, ptr %t87 + %t158 = call ptr @fn_sconcat(ptr @.str832, ptr %t157) + %t159 = call ptr @fn_sconcat(ptr %t156, ptr %t158) + %t160 = call ptr @fn_sconcat(ptr @.str831, ptr %t159) + %t161 = call ptr @fn_sconcat(ptr %t155, ptr %t160) + %t162 = call ptr @fn_emit_bind(ptr %t161) + store ptr %t162, ptr %t163 + %t164 = load ptr, ptr %t163 + %t165 = call ptr @fn_val(ptr %t164, ptr @.str833) + store ptr %t165, ptr %retval + br label %ret +ifend15: + %t166 = load ptr, ptr %t0 + %t167 = getelementptr inbounds %Str_Node, ptr %t166, i32 0, i32 1 + %t168 = load ptr, ptr %t167 + %t169 = call ptr @fn_arith_code(ptr %t168) + %t170 = load ptr, ptr %t22 + %t171 = getelementptr inbounds %Str_Val, ptr %t170, i32 0, i32 0 + %t172 = load ptr, ptr %t171 + %t173 = load ptr, ptr %t27 + %t174 = getelementptr inbounds %Str_Val, ptr %t173, i32 0, i32 0 + %t175 = load ptr, ptr %t174 + %t176 = call ptr @fn_sconcat(ptr @.str835, ptr %t175) + %t177 = call ptr @fn_sconcat(ptr %t172, ptr %t176) + %t178 = call ptr @fn_sconcat(ptr @.str834, ptr %t177) + %t179 = call ptr @fn_sconcat(ptr %t169, ptr %t178) + %t180 = call ptr @fn_emit_bind(ptr %t179) + store ptr %t180, ptr %t181 + %t182 = load ptr, ptr %t181 + %t183 = call ptr @fn_val(ptr %t182, ptr @.str836) + store ptr %t183, ptr %retval + br label %ret +ret: + %t184 = load ptr, ptr %retval + ret ptr %t184 +} + +define ptr @fn_emit_call(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t6 = alloca ptr + %t68 = alloca ptr + %t87 = alloca ptr + %t115 = alloca ptr + %t117 = alloca ptr + %t124 = alloca ptr + %t140 = alloca ptr + %t147 = alloca ptr + %t148 = alloca i32 + %t167 = alloca ptr + %t218 = alloca ptr + %t219 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 1 + %t5 = load ptr, ptr %t4 + store ptr %t5, ptr %t6 + %t7 = load ptr, ptr %t6 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str837) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then0, label %ifend2 +then0: + %t10 = load i32, ptr @g_nself + %t11 = icmp eq i32 %t10, 0 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then3, label %ifend5 +then3: + %t14 = call ptr @fn_val(ptr @.str838, ptr @.str839) + store ptr %t14, ptr %retval + br label %ret +ifend5: + %t15 = load ptr, ptr @g_self_stk + %t16 = getelementptr inbounds %LSlice, ptr %t15, i32 0, i32 0 + %t17 = load ptr, ptr %t16 + %t18 = load i32, ptr @g_nself + %t19 = sub i32 %t18, 1 + %t20 = getelementptr inbounds ptr, ptr %t17, i32 %t19 + %t21 = load ptr, ptr %t20 + %t22 = call ptr @fn_sconcat(ptr @.str840, ptr %t21) + %t23 = call ptr @fn_emit_bind(ptr %t22) + %t24 = call ptr @fn_val(ptr %t23, ptr @.str841) + store ptr %t24, ptr %retval + br label %ret +ifend2: + %t25 = load ptr, ptr %t6 + %t26 = call i32 @fn_streq(ptr %t25, ptr @.str842) + %t27 = icmp ne i32 %t26, 0 + br i1 %t27, label %then6, label %ifend8 +then6: + %t28 = call ptr @fn_emit_bind(ptr @.str843) + %t29 = call ptr @fn_val(ptr %t28, ptr @.str844) + store ptr %t29, ptr %retval + br label %ret +ifend8: + %t30 = load ptr, ptr %t6 + %t31 = call i32 @fn_streq(ptr %t30, ptr @.str845) + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then9, label %ifend11 +then9: + call void @fn_emit(ptr @.str846) + %t33 = call ptr @fn_val(ptr @.str847, ptr @.str848) + store ptr %t33, ptr %retval + br label %ret +ifend11: + %t34 = load ptr, ptr %t6 + %t35 = call i32 @fn_streq(ptr %t34, ptr @.str849) + %t36 = icmp ne i32 %t35, 0 + br i1 %t36, label %then12, label %ifend14 +then12: + call void @fn_emit(ptr @.str850) + %t37 = call ptr @fn_val(ptr @.str851, ptr @.str852) + store ptr %t37, ptr %retval + br label %ret +ifend14: + %t38 = load ptr, ptr %t6 + %t39 = call i32 @fn_streq(ptr %t38, ptr @.str853) + %t40 = icmp ne i32 %t39, 0 + br i1 %t40, label %then15, label %ifend17 +then15: + %t41 = call ptr @fn_emit_bind(ptr @.str854) + %t42 = call ptr @fn_val(ptr %t41, ptr @.str855) + store ptr %t42, ptr %retval + br label %ret +ifend17: + %t43 = load ptr, ptr %t6 + %t44 = call i32 @fn_streq(ptr %t43, ptr @.str856) + %t45 = icmp ne i32 %t44, 0 + br i1 %t45, label %then18, label %ifend20 +then18: + call void @fn_emit(ptr @.str857) + %t46 = call ptr @fn_val(ptr @.str858, ptr @.str859) + store ptr %t46, ptr %retval + br label %ret +ifend20: + %t47 = load ptr, ptr %t6 + %t48 = call i32 @fn_streq(ptr %t47, ptr @.str860) + %t49 = icmp ne i32 %t48, 0 + br i1 %t49, label %then21, label %ifend23 +then21: + %t50 = load ptr, ptr %t0 + %t51 = call ptr @fn_emit_len(ptr %t50) + store ptr %t51, ptr %retval + br label %ret +ifend23: + %t52 = load ptr, ptr %t6 + %t53 = call i32 @fn_streq(ptr %t52, ptr @.str861) + %t54 = icmp ne i32 %t53, 0 + br i1 %t54, label %then24, label %ifend26 +then24: + %t55 = load ptr, ptr %t0 + %t56 = call ptr @fn_emit_push(ptr %t55) + store ptr %t56, ptr %retval + br label %ret +ifend26: + %t57 = load ptr, ptr %t6 + %t58 = call i32 @fn_streq(ptr %t57, ptr @.str862) + %t59 = icmp ne i32 %t58, 0 + br i1 %t59, label %then27, label %ifend29 +then27: + %t60 = load ptr, ptr %t0 + %t61 = getelementptr inbounds %Str_Node, ptr %t60, i32 0, i32 7 + %t62 = load ptr, ptr %t61 + %t63 = getelementptr inbounds %LSlice, ptr %t62, i32 0, i32 0 + %t64 = load ptr, ptr %t63 + %t65 = getelementptr inbounds ptr, ptr %t64, i32 0 + %t66 = load ptr, ptr %t65 + %t67 = call ptr @fn_emit_expr(ptr %t66) + store ptr %t67, ptr %t68 + %t69 = load ptr, ptr %t68 + %t70 = getelementptr inbounds %Str_Val, ptr %t69, i32 0, i32 0 + %t71 = load ptr, ptr %t70 + %t72 = call ptr @fn_sconcat(ptr %t71, ptr @.str864) + %t73 = call ptr @fn_sconcat(ptr @.str863, ptr %t72) + %t74 = call ptr @fn_emit_bind(ptr %t73) + %t75 = call ptr @fn_val(ptr %t74, ptr @.str865) + store ptr %t75, ptr %retval + br label %ret +ifend29: + %t76 = load ptr, ptr %t6 + %t77 = call i32 @fn_streq(ptr %t76, ptr @.str866) + %t78 = icmp ne i32 %t77, 0 + br i1 %t78, label %then30, label %ifend32 +then30: + %t79 = load ptr, ptr %t0 + %t80 = getelementptr inbounds %Str_Node, ptr %t79, i32 0, i32 7 + %t81 = load ptr, ptr %t80 + %t82 = getelementptr inbounds %LSlice, ptr %t81, i32 0, i32 0 + %t83 = load ptr, ptr %t82 + %t84 = getelementptr inbounds ptr, ptr %t83, i32 0 + %t85 = load ptr, ptr %t84 + %t86 = call ptr @fn_emit_expr(ptr %t85) + store ptr %t86, ptr %t87 + %t88 = load ptr, ptr %t87 + %t89 = getelementptr inbounds %Str_Val, ptr %t88, i32 0, i32 0 + %t90 = load ptr, ptr %t89 + %t91 = call ptr @fn_sconcat(ptr %t90, ptr @.str868) + %t92 = call ptr @fn_sconcat(ptr @.str867, ptr %t91) + %t93 = call ptr @fn_emit_bind(ptr %t92) + %t94 = call ptr @fn_val(ptr %t93, ptr @.str869) + store ptr %t94, ptr %retval + br label %ret +ifend32: + %t95 = load ptr, ptr %t6 + %t96 = call i32 @fn_is_intrinsic(ptr %t95) + %t97 = icmp ne i32 %t96, 0 + br i1 %t97, label %then33, label %ifend35 +then33: + %t98 = load ptr, ptr %t6 + %t99 = load ptr, ptr %t0 + %t100 = call ptr @fn_emit_intrinsic(ptr %t98, ptr %t99) + store ptr %t100, ptr %retval + br label %ret +ifend35: + %t101 = load ptr, ptr %t6 + %t102 = call i32 @fn_is_intrinsic2(ptr %t101) + %t103 = icmp ne i32 %t102, 0 + br i1 %t103, label %then36, label %ifend38 +then36: + %t104 = load ptr, ptr %t6 + %t105 = load ptr, ptr %t0 + %t106 = call ptr @fn_emit_intrinsic2(ptr %t104, ptr %t105) + store ptr %t106, ptr %retval + br label %ret +ifend38: + %t107 = load ptr, ptr %t6 + %t108 = call i32 @fn_is_math_builtin(ptr %t107) + %t109 = icmp ne i32 %t108, 0 + br i1 %t109, label %then39, label %ifend41 +then39: + %t110 = load ptr, ptr %t6 + %t111 = load ptr, ptr %t0 + %t112 = call ptr @fn_emit_math_builtin(ptr %t110, ptr %t111) + store ptr %t112, ptr %retval + br label %ret +ifend41: + %t113 = load ptr, ptr %t6 + %t114 = call ptr @fn_find_fn(ptr %t113) + store ptr %t114, ptr %t115 + %t116 = load ptr, ptr %t6 + store ptr %t116, ptr %t117 + %t118 = load ptr, ptr %t115 + %t119 = icmp eq ptr %t118, null + %t120 = zext i1 %t119 to i32 + %t121 = icmp ne i32 %t120, 0 + br i1 %t121, label %then42, label %ifend44 +then42: + %t122 = load ptr, ptr %t6 + %t123 = call ptr @fn_sconcat(ptr @.str870, ptr %t122) + store ptr %t123, ptr %t124 + %t125 = load ptr, ptr %t124 + %t126 = call ptr @fn_find_fn(ptr %t125) + store ptr %t126, ptr %t115 + %t127 = load ptr, ptr %t115 + %t128 = icmp eq ptr %t127, null + %t129 = zext i1 %t128 to i32 + %t130 = icmp ne i32 %t129, 0 + br i1 %t130, label %then45, label %ifend47 +then45: + %t131 = load ptr, ptr %t6 + %t132 = call ptr @fn_sconcat(ptr @.str871, ptr %t131) + call void @fn_perr(ptr %t132) + br label %ifend47 +ifend47: + %t133 = load ptr, ptr %t124 + store ptr %t133, ptr %t117 + br label %ifend44 +ifend44: + %t134 = getelementptr %LSlice, ptr null, i32 1 + %t135 = ptrtoint ptr %t134 to i64 + %t136 = call ptr @malloc(i64 %t135) + %t137 = getelementptr inbounds %LSlice, ptr %t136, i32 0, i32 0 + store ptr null, ptr %t137 + %t138 = getelementptr inbounds %LSlice, ptr %t136, i32 0, i32 1 + store i32 0, ptr %t138 + %t139 = getelementptr inbounds %LSlice, ptr %t136, i32 0, i32 2 + store i32 0, ptr %t139 + store ptr %t136, ptr %t140 + %t141 = getelementptr %LSlice, ptr null, i32 1 + %t142 = ptrtoint ptr %t141 to i64 + %t143 = call ptr @malloc(i64 %t142) + %t144 = getelementptr inbounds %LSlice, ptr %t143, i32 0, i32 0 + store ptr null, ptr %t144 + %t145 = getelementptr inbounds %LSlice, ptr %t143, i32 0, i32 1 + store i32 0, ptr %t145 + %t146 = getelementptr inbounds %LSlice, ptr %t143, i32 0, i32 2 + store i32 0, ptr %t146 + store ptr %t143, ptr %t147 + store i32 0, ptr %t148 + br label %wcond48 +wcond48: + %t149 = load i32, ptr %t148 + %t150 = load ptr, ptr %t0 + %t151 = getelementptr inbounds %Str_Node, ptr %t150, i32 0, i32 7 + %t152 = load ptr, ptr %t151 + %t153 = getelementptr inbounds %LSlice, ptr %t152, i32 0, i32 1 + %t154 = load i32, ptr %t153 + %t155 = icmp slt i32 %t149, %t154 + %t156 = zext i1 %t155 to i32 + %t157 = icmp ne i32 %t156, 0 + br i1 %t157, label %wbody49, label %wend50 +wbody49: + %t158 = load ptr, ptr %t0 + %t159 = getelementptr inbounds %Str_Node, ptr %t158, i32 0, i32 7 + %t160 = load ptr, ptr %t159 + %t161 = getelementptr inbounds %LSlice, ptr %t160, i32 0, i32 0 + %t162 = load ptr, ptr %t161 + %t163 = load i32, ptr %t148 + %t164 = getelementptr inbounds ptr, ptr %t162, i32 %t163 + %t165 = load ptr, ptr %t164 + %t166 = call ptr @fn_emit_expr(ptr %t165) + store ptr %t166, ptr %t167 + %t168 = load ptr, ptr %t140 + %t169 = getelementptr inbounds %LSlice, ptr %t168, i32 0, i32 1 + %t170 = getelementptr inbounds %LSlice, ptr %t168, i32 0, i32 2 + %t171 = getelementptr inbounds %LSlice, ptr %t168, i32 0, i32 0 + %t172 = load i32, ptr %t169 + %t173 = load i32, ptr %t170 + %t174 = icmp sge i32 %t172, %t173 + br i1 %t174, label %grow51, label %put52 +grow51: + %t175 = mul i32 %t173, 2 + %t176 = icmp eq i32 %t173, 0 + %t177 = select i1 %t176, i32 8, i32 %t175 + %t178 = getelementptr ptr, ptr null, i32 1 + %t179 = ptrtoint ptr %t178 to i64 + %t180 = zext i32 %t177 to i64 + %t181 = mul i64 %t180, %t179 + %t182 = load ptr, ptr %t171 + %t183 = call ptr @realloc(ptr %t182, i64 %t181) + store ptr %t183, ptr %t171 + store i32 %t177, ptr %t170 + br label %put52 +put52: + %t184 = load ptr, ptr %t167 + %t185 = getelementptr inbounds %Str_Val, ptr %t184, i32 0, i32 0 + %t186 = load ptr, ptr %t185 + %t187 = load ptr, ptr %t171 + %t188 = getelementptr inbounds ptr, ptr %t187, i32 %t172 + store ptr %t186, ptr %t188 + %t189 = add i32 %t172, 1 + store i32 %t189, ptr %t169 + %t190 = load ptr, ptr %t147 + %t191 = getelementptr inbounds %LSlice, ptr %t190, i32 0, i32 1 + %t192 = getelementptr inbounds %LSlice, ptr %t190, i32 0, i32 2 + %t193 = getelementptr inbounds %LSlice, ptr %t190, i32 0, i32 0 + %t194 = load i32, ptr %t191 + %t195 = load i32, ptr %t192 + %t196 = icmp sge i32 %t194, %t195 + br i1 %t196, label %grow53, label %put54 +grow53: + %t197 = mul i32 %t195, 2 + %t198 = icmp eq i32 %t195, 0 + %t199 = select i1 %t198, i32 8, i32 %t197 + %t200 = getelementptr ptr, ptr null, i32 1 + %t201 = ptrtoint ptr %t200 to i64 + %t202 = zext i32 %t199 to i64 + %t203 = mul i64 %t202, %t201 + %t204 = load ptr, ptr %t193 + %t205 = call ptr @realloc(ptr %t204, i64 %t203) + store ptr %t205, ptr %t193 + store i32 %t199, ptr %t192 + br label %put54 +put54: + %t206 = load ptr, ptr %t167 + %t207 = getelementptr inbounds %Str_Val, ptr %t206, i32 0, i32 1 + %t208 = load ptr, ptr %t207 + %t209 = load ptr, ptr %t193 + %t210 = getelementptr inbounds ptr, ptr %t209, i32 %t194 + store ptr %t208, ptr %t210 + %t211 = add i32 %t194, 1 + store i32 %t211, ptr %t191 + %t212 = load i32, ptr %t148 + %t213 = add i32 %t212, 1 + store i32 %t213, ptr %t148 + br label %wcond48 +wend50: + %t214 = load ptr, ptr %t115 + %t215 = getelementptr inbounds %Str_Node, ptr %t214, i32 0, i32 3 + %t216 = load ptr, ptr %t215 + %t217 = call ptr @fn_llty(ptr %t216) + store ptr %t217, ptr %t218 + call void @fn_emit(ptr @.str872) + store ptr @.str873, ptr %t219 + %t220 = load ptr, ptr %t218 + %t221 = call i32 @fn_streq(ptr %t220, ptr @.str874) + %t222 = icmp eq i32 %t221, 0 + %t223 = zext i1 %t222 to i32 + %t224 = icmp ne i32 %t223, 0 + br i1 %t224, label %then55, label %ifend57 +then55: + %t225 = call ptr @fn_nreg() + store ptr %t225, ptr %t219 + %t226 = load ptr, ptr %t219 + call void @fn_emit(ptr %t226) + call void @fn_emit(ptr @.str875) + br label %ifend57 +ifend57: + call void @fn_emit(ptr @.str876) + %t227 = load ptr, ptr %t218 + call void @fn_emit(ptr %t227) + call void @fn_emit(ptr @.str877) + %t228 = load ptr, ptr %t117 + call void @fn_emit(ptr %t228) + call void @fn_emit(ptr @.str878) + store i32 0, ptr %t148 + br label %wcond58 +wcond58: + %t229 = load i32, ptr %t148 + %t230 = load ptr, ptr %t140 + %t231 = getelementptr inbounds %LSlice, ptr %t230, i32 0, i32 1 + %t232 = load i32, ptr %t231 + %t233 = icmp slt i32 %t229, %t232 + %t234 = zext i1 %t233 to i32 + %t235 = icmp ne i32 %t234, 0 + br i1 %t235, label %wbody59, label %wend60 +wbody59: + %t236 = load i32, ptr %t148 + %t237 = icmp sgt i32 %t236, 0 + %t238 = zext i1 %t237 to i32 + %t239 = icmp ne i32 %t238, 0 + br i1 %t239, label %then61, label %ifend63 +then61: + call void @fn_emit(ptr @.str879) + br label %ifend63 +ifend63: + %t240 = load ptr, ptr %t147 + %t241 = getelementptr inbounds %LSlice, ptr %t240, i32 0, i32 0 + %t242 = load ptr, ptr %t241 + %t243 = load i32, ptr %t148 + %t244 = getelementptr inbounds ptr, ptr %t242, i32 %t243 + %t245 = load ptr, ptr %t244 + %t246 = call ptr @fn_llty(ptr %t245) + call void @fn_emit(ptr %t246) + call void @fn_emit(ptr @.str880) + %t247 = load ptr, ptr %t140 + %t248 = getelementptr inbounds %LSlice, ptr %t247, i32 0, i32 0 + %t249 = load ptr, ptr %t248 + %t250 = load i32, ptr %t148 + %t251 = getelementptr inbounds ptr, ptr %t249, i32 %t250 + %t252 = load ptr, ptr %t251 + call void @fn_emit(ptr %t252) + %t253 = load i32, ptr %t148 + %t254 = add i32 %t253, 1 + store i32 %t254, ptr %t148 + br label %wcond58 +wend60: + call void @fn_emit(ptr @.str881) + %t255 = load ptr, ptr %t219 + %t256 = load ptr, ptr %t115 + %t257 = getelementptr inbounds %Str_Node, ptr %t256, i32 0, i32 3 + %t258 = load ptr, ptr %t257 + %t259 = call ptr @fn_val(ptr %t255, ptr %t258) + store ptr %t259, ptr %retval + br label %ret +ret: + %t260 = load ptr, ptr %retval + ret ptr %t260 +} + +define ptr @fn_emit_expr(ptr %arg_e) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t79 = alloca i32 + %t101 = alloca ptr + %t132 = alloca ptr + %t161 = alloca ptr + %t173 = alloca ptr + %t203 = alloca ptr + %t221 = alloca ptr + store ptr %arg_e, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = icmp eq ptr %t1, null + %t3 = zext i1 %t2 to i32 + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + %t5 = call ptr @fn_val(ptr @.str882, ptr @.str883) + store ptr %t5, ptr %retval + br label %ret +ifend2: + %t6 = load ptr, ptr %t0 + %t7 = getelementptr inbounds %Str_Node, ptr %t6, i32 0, i32 0 + %t8 = load i32, ptr %t7 + %t9 = icmp eq i32 %t8, 30 + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %then3, label %ifend5 +then3: + %t12 = load ptr, ptr %t0 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 2 + %t14 = load i32, ptr %t13 + %t15 = call ptr @fn_itoa(i32 %t14) + %t16 = call ptr @fn_val(ptr %t15, ptr @.str884) + store ptr %t16, ptr %retval + br label %ret +ifend5: + %t17 = load ptr, ptr %t0 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 40 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + br i1 %t22, label %then6, label %ifend8 +then6: + %t23 = load ptr, ptr %t0 + %t24 = getelementptr inbounds %Str_Node, ptr %t23, i32 0, i32 2 + %t25 = load i32, ptr %t24 + %t26 = call ptr @fn_itoa(i32 %t25) + %t27 = call ptr @fn_val(ptr %t26, ptr @.str885) + store ptr %t27, ptr %retval + br label %ret +ifend8: + %t28 = load ptr, ptr %t0 + %t29 = getelementptr inbounds %Str_Node, ptr %t28, i32 0, i32 0 + %t30 = load i32, ptr %t29 + %t31 = icmp eq i32 %t30, 32 + %t32 = zext i1 %t31 to i32 + %t33 = icmp ne i32 %t32, 0 + br i1 %t33, label %then9, label %ifend11 +then9: + %t34 = load ptr, ptr %t0 + %t35 = getelementptr inbounds %Str_Node, ptr %t34, i32 0, i32 2 + %t36 = load i32, ptr %t35 + %t37 = call ptr @fn_itoa(i32 %t36) + %t38 = call ptr @fn_val(ptr %t37, ptr @.str886) + store ptr %t38, ptr %retval + br label %ret +ifend11: + %t39 = load ptr, ptr %t0 + %t40 = getelementptr inbounds %Str_Node, ptr %t39, i32 0, i32 0 + %t41 = load i32, ptr %t40 + %t42 = icmp eq i32 %t41, 31 + %t43 = zext i1 %t42 to i32 + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then12, label %ifend14 +then12: + %t45 = load ptr, ptr %t0 + %t46 = getelementptr inbounds %Str_Node, ptr %t45, i32 0, i32 1 + %t47 = load ptr, ptr %t46 + %t48 = call ptr @fn_emit_str_const(ptr %t47) + %t49 = call ptr @fn_val(ptr %t48, ptr @.str887) + store ptr %t49, ptr %retval + br label %ret +ifend14: + %t50 = load ptr, ptr %t0 + %t51 = getelementptr inbounds %Str_Node, ptr %t50, i32 0, i32 0 + %t52 = load i32, ptr %t51 + %t53 = icmp eq i32 %t52, 39 + %t54 = zext i1 %t53 to i32 + %t55 = icmp ne i32 %t54, 0 + br i1 %t55, label %then15, label %ifend17 +then15: + %t56 = load ptr, ptr %t0 + %t57 = getelementptr inbounds %Str_Node, ptr %t56, i32 0, i32 1 + %t58 = load ptr, ptr %t57 + %t59 = call i32 @fn_is_slice_ty(ptr %t58) + %t60 = icmp ne i32 %t59, 0 + br i1 %t60, label %then18, label %ifend20 +then18: + %t61 = load ptr, ptr %t0 + %t62 = getelementptr inbounds %Str_Node, ptr %t61, i32 0, i32 1 + %t63 = load ptr, ptr %t62 + %t64 = call ptr @fn_emit_new_slice(ptr %t63) + store ptr %t64, ptr %retval + br label %ret +ifend20: + %t65 = load ptr, ptr %t0 + %t66 = getelementptr inbounds %Str_Node, ptr %t65, i32 0, i32 1 + %t67 = load ptr, ptr %t66 + %t68 = call ptr @fn_emit_new_struct(ptr %t67) + store ptr %t68, ptr %retval + br label %ret +ifend17: + %t69 = load ptr, ptr %t0 + %t70 = getelementptr inbounds %Str_Node, ptr %t69, i32 0, i32 0 + %t71 = load i32, ptr %t70 + %t72 = icmp eq i32 %t71, 33 + %t73 = zext i1 %t72 to i32 + %t74 = icmp ne i32 %t73, 0 + br i1 %t74, label %then21, label %ifend23 +then21: + %t75 = load ptr, ptr %t0 + %t76 = getelementptr inbounds %Str_Node, ptr %t75, i32 0, i32 1 + %t77 = load ptr, ptr %t76 + %t78 = call i32 @fn_loc_find(ptr %t77) + store i32 %t78, ptr %t79 + %t80 = load i32, ptr %t79 + %t81 = icmp sge i32 %t80, 0 + %t82 = zext i1 %t81 to i32 + %t83 = icmp ne i32 %t82, 0 + br i1 %t83, label %then24, label %ifend26 +then24: + %t84 = load ptr, ptr @g_loc_reg + %t85 = getelementptr inbounds %LSlice, ptr %t84, i32 0, i32 0 + %t86 = load ptr, ptr %t85 + %t87 = load i32, ptr %t79 + %t88 = getelementptr inbounds ptr, ptr %t86, i32 %t87 + %t89 = load ptr, ptr %t88 + %t90 = load ptr, ptr @g_loc_ty + %t91 = getelementptr inbounds %LSlice, ptr %t90, i32 0, i32 0 + %t92 = load ptr, ptr %t91 + %t93 = load i32, ptr %t79 + %t94 = getelementptr inbounds ptr, ptr %t92, i32 %t93 + %t95 = load ptr, ptr %t94 + %t96 = call ptr @fn_emit_load_at(ptr %t89, ptr %t95) + store ptr %t96, ptr %retval + br label %ret +ifend26: + %t97 = load ptr, ptr %t0 + %t98 = getelementptr inbounds %Str_Node, ptr %t97, i32 0, i32 1 + %t99 = load ptr, ptr %t98 + %t100 = call ptr @fn_find_global(ptr %t99) + store ptr %t100, ptr %t101 + %t102 = load ptr, ptr %t101 + %t103 = icmp eq ptr %t102, null + %t104 = zext i1 %t103 to i32 + %t105 = icmp eq i32 %t104, 0 + %t106 = zext i1 %t105 to i32 + %t107 = icmp ne i32 %t106, 0 + br i1 %t107, label %then27, label %ifend29 +then27: + %t108 = load ptr, ptr %t101 + %t109 = getelementptr inbounds %Str_Node, ptr %t108, i32 0, i32 0 + %t110 = load i32, ptr %t109 + %t111 = icmp eq i32 %t110, 3 + %t112 = zext i1 %t111 to i32 + %t113 = icmp ne i32 %t112, 0 + br i1 %t113, label %then30, label %ifend32 +then30: + %t114 = load ptr, ptr %t101 + %t115 = getelementptr inbounds %Str_Node, ptr %t114, i32 0, i32 4 + %t116 = load ptr, ptr %t115 + %t117 = getelementptr inbounds %Str_Node, ptr %t116, i32 0, i32 2 + %t118 = load i32, ptr %t117 + %t119 = call ptr @fn_itoa(i32 %t118) + %t120 = call ptr @fn_val(ptr %t119, ptr @.str888) + store ptr %t120, ptr %retval + br label %ret +ifend32: + %t121 = load ptr, ptr %t101 + %t122 = getelementptr inbounds %Str_Node, ptr %t121, i32 0, i32 3 + %t123 = load ptr, ptr %t122 + %t124 = call ptr @fn_llty(ptr %t123) + %t125 = load ptr, ptr %t0 + %t126 = getelementptr inbounds %Str_Node, ptr %t125, i32 0, i32 1 + %t127 = load ptr, ptr %t126 + %t128 = call ptr @fn_sconcat(ptr @.str890, ptr %t127) + %t129 = call ptr @fn_sconcat(ptr %t124, ptr %t128) + %t130 = call ptr @fn_sconcat(ptr @.str889, ptr %t129) + %t131 = call ptr @fn_emit_bind(ptr %t130) + store ptr %t131, ptr %t132 + %t133 = load ptr, ptr %t132 + %t134 = load ptr, ptr %t101 + %t135 = getelementptr inbounds %Str_Node, ptr %t134, i32 0, i32 3 + %t136 = load ptr, ptr %t135 + %t137 = call ptr @fn_val(ptr %t133, ptr %t136) + store ptr %t137, ptr %retval + br label %ret +ifend29: + %t138 = load ptr, ptr %t0 + %t139 = getelementptr inbounds %Str_Node, ptr %t138, i32 0, i32 1 + %t140 = load ptr, ptr %t139 + %t141 = call i32 @fn_is_ui_ident(ptr %t140) + %t142 = icmp ne i32 %t141, 0 + br i1 %t142, label %then33, label %ifend35 +then33: + %t143 = load ptr, ptr %t0 + %t144 = getelementptr inbounds %Str_Node, ptr %t143, i32 0, i32 1 + %t145 = load ptr, ptr %t144 + %t146 = call i32 @fn_ui_index_of(ptr %t145) + %t147 = call ptr @fn_itoa(i32 %t146) + %t148 = call ptr @fn_val(ptr %t147, ptr @.str891) + store ptr %t148, ptr %retval + br label %ret +ifend35: + %t149 = load ptr, ptr %t0 + %t150 = getelementptr inbounds %Str_Node, ptr %t149, i32 0, i32 1 + %t151 = load ptr, ptr %t150 + %t152 = call ptr @fn_sconcat(ptr @.str892, ptr %t151) + call void @fn_perr(ptr %t152) + br label %ifend23 +ifend23: + %t153 = load ptr, ptr %t0 + %t154 = getelementptr inbounds %Str_Node, ptr %t153, i32 0, i32 0 + %t155 = load i32, ptr %t154 + %t156 = icmp eq i32 %t155, 35 + %t157 = zext i1 %t156 to i32 + %t158 = icmp ne i32 %t157, 0 + br i1 %t158, label %then36, label %ifend38 +then36: + %t159 = load ptr, ptr %t0 + %t160 = call ptr @fn_emit_member_addr(ptr %t159) + store ptr %t160, ptr %t161 + %t162 = load ptr, ptr %t161 + %t163 = load ptr, ptr @g_g_addr_ty + %t164 = call ptr @fn_emit_load_at(ptr %t162, ptr %t163) + store ptr %t164, ptr %retval + br label %ret +ifend38: + %t165 = load ptr, ptr %t0 + %t166 = getelementptr inbounds %Str_Node, ptr %t165, i32 0, i32 0 + %t167 = load i32, ptr %t166 + %t168 = icmp eq i32 %t167, 36 + %t169 = zext i1 %t168 to i32 + %t170 = icmp ne i32 %t169, 0 + br i1 %t170, label %then39, label %ifend41 +then39: + %t171 = load ptr, ptr %t0 + %t172 = call ptr @fn_emit_index_addr(ptr %t171) + store ptr %t172, ptr %t173 + %t174 = load ptr, ptr %t173 + %t175 = load ptr, ptr @g_g_addr_ty + %t176 = call ptr @fn_emit_load_at(ptr %t174, ptr %t175) + store ptr %t176, ptr %retval + br label %ret +ifend41: + %t177 = load ptr, ptr %t0 + %t178 = getelementptr inbounds %Str_Node, ptr %t177, i32 0, i32 0 + %t179 = load i32, ptr %t178 + %t180 = icmp eq i32 %t179, 34 + %t181 = zext i1 %t180 to i32 + %t182 = icmp ne i32 %t181, 0 + br i1 %t182, label %then42, label %ifend44 +then42: + %t183 = load ptr, ptr %t0 + %t184 = call ptr @fn_emit_call(ptr %t183) + store ptr %t184, ptr %retval + br label %ret +ifend44: + %t185 = load ptr, ptr %t0 + %t186 = getelementptr inbounds %Str_Node, ptr %t185, i32 0, i32 0 + %t187 = load i32, ptr %t186 + %t188 = icmp eq i32 %t187, 37 + %t189 = zext i1 %t188 to i32 + %t190 = icmp ne i32 %t189, 0 + br i1 %t190, label %then45, label %ifend47 +then45: + %t191 = load ptr, ptr %t0 + %t192 = call ptr @fn_emit_bin(ptr %t191) + store ptr %t192, ptr %retval + br label %ret +ifend47: + %t193 = load ptr, ptr %t0 + %t194 = getelementptr inbounds %Str_Node, ptr %t193, i32 0, i32 0 + %t195 = load i32, ptr %t194 + %t196 = icmp eq i32 %t195, 38 + %t197 = zext i1 %t196 to i32 + %t198 = icmp ne i32 %t197, 0 + br i1 %t198, label %then48, label %ifend50 +then48: + %t199 = load ptr, ptr %t0 + %t200 = getelementptr inbounds %Str_Node, ptr %t199, i32 0, i32 4 + %t201 = load ptr, ptr %t200 + %t202 = call ptr @fn_emit_expr(ptr %t201) + store ptr %t202, ptr %t203 + %t204 = load ptr, ptr %t0 + %t205 = getelementptr inbounds %Str_Node, ptr %t204, i32 0, i32 1 + %t206 = load ptr, ptr %t205 + %t207 = call i32 @fn_streq(ptr %t206, ptr @.str893) + %t208 = icmp ne i32 %t207, 0 + br i1 %t208, label %then51, label %ifend53 +then51: + %t209 = load ptr, ptr %t203 + %t210 = getelementptr inbounds %Str_Val, ptr %t209, i32 0, i32 0 + %t211 = load ptr, ptr %t210 + %t212 = call ptr @fn_sconcat(ptr @.str894, ptr %t211) + %t213 = call ptr @fn_emit_bind(ptr %t212) + %t214 = call ptr @fn_val(ptr %t213, ptr @.str895) + store ptr %t214, ptr %retval + br label %ret +ifend53: + %t215 = load ptr, ptr %t203 + %t216 = getelementptr inbounds %Str_Val, ptr %t215, i32 0, i32 0 + %t217 = load ptr, ptr %t216 + %t218 = call ptr @fn_sconcat(ptr %t217, ptr @.str897) + %t219 = call ptr @fn_sconcat(ptr @.str896, ptr %t218) + %t220 = call ptr @fn_emit_bind(ptr %t219) + store ptr %t220, ptr %t221 + %t222 = load ptr, ptr %t221 + %t223 = call ptr @fn_sconcat(ptr %t222, ptr @.str899) + %t224 = call ptr @fn_sconcat(ptr @.str898, ptr %t223) + %t225 = call ptr @fn_emit_bind(ptr %t224) + %t226 = call ptr @fn_val(ptr %t225, ptr @.str900) + store ptr %t226, ptr %retval + br label %ret +ifend50: + call void @fn_perr(ptr @.str901) + %t227 = call ptr @fn_val(ptr @.str902, ptr @.str903) + store ptr %t227, ptr %retval + br label %ret +ret: + %t228 = load ptr, ptr %retval + ret ptr %t228 +} + +define void @fn_emit_block(ptr %arg_b) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_b, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 7 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds %LSlice, ptr %t5, i32 0, i32 1 + %t7 = load i32, ptr %t6 + %t8 = icmp slt i32 %t2, %t7 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t11 = load i32, ptr @g_g_term + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then3, label %ifend5 +then3: + br label %ret +ifend5: + %t13 = load ptr, ptr %t0 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 7 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %LSlice, ptr %t15, i32 0, i32 0 + %t17 = load ptr, ptr %t16 + %t18 = load i32, ptr %t1 + %t19 = getelementptr inbounds ptr, ptr %t17, i32 %t18 + %t20 = load ptr, ptr %t19 + call void @fn_emit_stmt(ptr %t20) + %t21 = load i32, ptr %t1 + %t22 = add i32 %t21, 1 + store i32 %t22, ptr %t1 + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define void @fn_store_at(ptr %arg_lt, ptr %arg_v, ptr %arg_addr) { +entry: + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca ptr + store ptr %arg_lt, ptr %t0 + store ptr %arg_v, ptr %t1 + store ptr %arg_addr, ptr %t2 + call void @fn_emit(ptr @.str904) + %t3 = load ptr, ptr %t0 + call void @fn_emit(ptr %t3) + call void @fn_emit(ptr @.str905) + %t4 = load ptr, ptr %t1 + call void @fn_emit(ptr %t4) + call void @fn_emit(ptr @.str906) + %t5 = load ptr, ptr %t2 + call void @fn_emit(ptr %t5) + call void @fn_emit(ptr @.str907) + br label %ret +ret: + ret void +} + +define void @fn_emit_assign(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t4 = alloca ptr + %t5 = alloca ptr + %t6 = alloca ptr + %t17 = alloca i32 + %t38 = alloca ptr + %t74 = alloca ptr + %t79 = alloca ptr + %t83 = alloca ptr + %t97 = alloca ptr + %t98 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + store ptr %t3, ptr %t4 + store ptr @.str908, ptr %t5 + store ptr @.str909, ptr %t6 + %t7 = load ptr, ptr %t4 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 0 + %t9 = load i32, ptr %t8 + %t10 = icmp eq i32 %t9, 33 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %else1 +then0: + %t13 = load ptr, ptr %t4 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 1 + %t15 = load ptr, ptr %t14 + %t16 = call i32 @fn_loc_find(ptr %t15) + store i32 %t16, ptr %t17 + %t18 = load i32, ptr %t17 + %t19 = icmp sge i32 %t18, 0 + %t20 = zext i1 %t19 to i32 + %t21 = icmp ne i32 %t20, 0 + br i1 %t21, label %then3, label %else4 +then3: + %t22 = load ptr, ptr @g_loc_reg + %t23 = getelementptr inbounds %LSlice, ptr %t22, i32 0, i32 0 + %t24 = load ptr, ptr %t23 + %t25 = load i32, ptr %t17 + %t26 = getelementptr inbounds ptr, ptr %t24, i32 %t25 + %t27 = load ptr, ptr %t26 + store ptr %t27, ptr %t5 + %t28 = load ptr, ptr @g_loc_ty + %t29 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 0 + %t30 = load ptr, ptr %t29 + %t31 = load i32, ptr %t17 + %t32 = getelementptr inbounds ptr, ptr %t30, i32 %t31 + %t33 = load ptr, ptr %t32 + store ptr %t33, ptr %t6 + br label %ifend5 +else4: + %t34 = load ptr, ptr %t4 + %t35 = getelementptr inbounds %Str_Node, ptr %t34, i32 0, i32 1 + %t36 = load ptr, ptr %t35 + %t37 = call ptr @fn_find_global(ptr %t36) + store ptr %t37, ptr %t38 + %t39 = load ptr, ptr %t38 + %t40 = icmp eq ptr %t39, null + %t41 = zext i1 %t40 to i32 + %t42 = icmp ne i32 %t41, 0 + br i1 %t42, label %then6, label %ifend8 +then6: + %t43 = load ptr, ptr %t4 + %t44 = getelementptr inbounds %Str_Node, ptr %t43, i32 0, i32 1 + %t45 = load ptr, ptr %t44 + %t46 = call ptr @fn_sconcat(ptr @.str910, ptr %t45) + call void @fn_perr(ptr %t46) + br label %ifend8 +ifend8: + %t47 = load ptr, ptr %t4 + %t48 = getelementptr inbounds %Str_Node, ptr %t47, i32 0, i32 1 + %t49 = load ptr, ptr %t48 + %t50 = call ptr @fn_sconcat(ptr @.str911, ptr %t49) + store ptr %t50, ptr %t5 + %t51 = load ptr, ptr %t38 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 3 + %t53 = load ptr, ptr %t52 + store ptr %t53, ptr %t6 + br label %ifend5 +ifend5: + br label %ifend2 +else1: + %t54 = load ptr, ptr %t4 + %t55 = getelementptr inbounds %Str_Node, ptr %t54, i32 0, i32 0 + %t56 = load i32, ptr %t55 + %t57 = icmp eq i32 %t56, 35 + %t58 = zext i1 %t57 to i32 + %t59 = icmp ne i32 %t58, 0 + br i1 %t59, label %then9, label %else10 +then9: + %t60 = load ptr, ptr %t4 + %t61 = call ptr @fn_emit_member_addr(ptr %t60) + store ptr %t61, ptr %t5 + %t62 = load ptr, ptr @g_g_addr_ty + store ptr %t62, ptr %t6 + br label %ifend11 +else10: + %t63 = load ptr, ptr %t4 + %t64 = getelementptr inbounds %Str_Node, ptr %t63, i32 0, i32 0 + %t65 = load i32, ptr %t64 + %t66 = icmp eq i32 %t65, 36 + %t67 = zext i1 %t66 to i32 + %t68 = icmp ne i32 %t67, 0 + br i1 %t68, label %then12, label %else13 +then12: + %t69 = load ptr, ptr %t4 + %t70 = call ptr @fn_emit_index_addr(ptr %t69) + store ptr %t70, ptr %t5 + %t71 = load ptr, ptr @g_g_addr_ty + store ptr %t71, ptr %t6 + br label %ifend14 +else13: + call void @fn_perr(ptr @.str912) + br label %ifend14 +ifend14: + br label %ifend11 +ifend11: + br label %ifend2 +ifend2: + %t72 = load ptr, ptr %t6 + %t73 = call ptr @fn_llty(ptr %t72) + store ptr %t73, ptr %t74 + %t75 = load ptr, ptr %t0 + %t76 = getelementptr inbounds %Str_Node, ptr %t75, i32 0, i32 5 + %t77 = load ptr, ptr %t76 + %t78 = call ptr @fn_emit_expr(ptr %t77) + store ptr %t78, ptr %t79 + %t80 = load ptr, ptr %t79 + %t81 = getelementptr inbounds %Str_Val, ptr %t80, i32 0, i32 0 + %t82 = load ptr, ptr %t81 + store ptr %t82, ptr %t83 + %t84 = load ptr, ptr %t0 + %t85 = getelementptr inbounds %Str_Node, ptr %t84, i32 0, i32 1 + %t86 = load ptr, ptr %t85 + %t87 = call i32 @fn_streq(ptr %t86, ptr @.str913) + %t88 = icmp eq i32 %t87, 0 + %t89 = zext i1 %t88 to i32 + %t90 = icmp ne i32 %t89, 0 + br i1 %t90, label %then15, label %ifend17 +then15: + %t91 = load ptr, ptr %t74 + %t92 = load ptr, ptr %t5 + %t93 = call ptr @fn_sconcat(ptr @.str915, ptr %t92) + %t94 = call ptr @fn_sconcat(ptr %t91, ptr %t93) + %t95 = call ptr @fn_sconcat(ptr @.str914, ptr %t94) + %t96 = call ptr @fn_emit_bind(ptr %t95) + store ptr %t96, ptr %t97 + store ptr @.str916, ptr %t98 + %t99 = load ptr, ptr %t0 + %t100 = getelementptr inbounds %Str_Node, ptr %t99, i32 0, i32 1 + %t101 = load ptr, ptr %t100 + %t102 = call i32 @fn_streq(ptr %t101, ptr @.str917) + %t103 = icmp ne i32 %t102, 0 + br i1 %t103, label %then18, label %ifend20 +then18: + store ptr @.str918, ptr %t98 + br label %ifend20 +ifend20: + %t104 = load ptr, ptr %t0 + %t105 = getelementptr inbounds %Str_Node, ptr %t104, i32 0, i32 1 + %t106 = load ptr, ptr %t105 + %t107 = call i32 @fn_streq(ptr %t106, ptr @.str919) + %t108 = icmp ne i32 %t107, 0 + br i1 %t108, label %then21, label %ifend23 +then21: + store ptr @.str920, ptr %t98 + br label %ifend23 +ifend23: + %t109 = load ptr, ptr %t0 + %t110 = getelementptr inbounds %Str_Node, ptr %t109, i32 0, i32 1 + %t111 = load ptr, ptr %t110 + %t112 = call i32 @fn_streq(ptr %t111, ptr @.str921) + %t113 = icmp ne i32 %t112, 0 + br i1 %t113, label %then24, label %ifend26 +then24: + store ptr @.str922, ptr %t98 + br label %ifend26 +ifend26: + %t114 = load ptr, ptr %t98 + %t115 = load ptr, ptr %t97 + %t116 = load ptr, ptr %t83 + %t117 = call ptr @fn_sconcat(ptr @.str924, ptr %t116) + %t118 = call ptr @fn_sconcat(ptr %t115, ptr %t117) + %t119 = call ptr @fn_sconcat(ptr @.str923, ptr %t118) + %t120 = call ptr @fn_sconcat(ptr %t114, ptr %t119) + %t121 = call ptr @fn_emit_bind(ptr %t120) + store ptr %t121, ptr %t83 + br label %ifend17 +ifend17: + %t122 = load ptr, ptr %t74 + %t123 = load ptr, ptr %t83 + %t124 = load ptr, ptr %t5 + call void @fn_store_at(ptr %t122, ptr %t123, ptr %t124) + br label %ret +ret: + ret void +} + +define void @fn_emit_if(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t5 = alloca ptr + %t12 = alloca ptr + %t20 = alloca i32 + %t22 = alloca ptr + %t24 = alloca ptr + %t26 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_emit_expr(ptr %t3) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Val, ptr %t6, i32 0, i32 0 + %t8 = load ptr, ptr %t7 + %t9 = call ptr @fn_sconcat(ptr %t8, ptr @.str926) + %t10 = call ptr @fn_sconcat(ptr @.str925, ptr %t9) + %t11 = call ptr @fn_emit_bind(ptr %t10) + store ptr %t11, ptr %t12 + %t13 = load ptr, ptr %t0 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 6 + %t15 = load ptr, ptr %t14 + %t16 = icmp eq ptr %t15, null + %t17 = zext i1 %t16 to i32 + %t18 = icmp eq i32 %t17, 0 + %t19 = zext i1 %t18 to i32 + store i32 %t19, ptr %t20 + %t21 = call ptr @fn_lbl(ptr @.str927) + store ptr %t21, ptr %t22 + %t23 = call ptr @fn_lbl(ptr @.str928) + store ptr %t23, ptr %t24 + %t25 = call ptr @fn_lbl(ptr @.str929) + store ptr %t25, ptr %t26 + %t27 = load i32, ptr %t20 + %t28 = icmp ne i32 %t27, 0 + br i1 %t28, label %then0, label %else1 +then0: + call void @fn_emit(ptr @.str930) + %t29 = load ptr, ptr %t12 + call void @fn_emit(ptr %t29) + call void @fn_emit(ptr @.str931) + %t30 = load ptr, ptr %t22 + call void @fn_emit(ptr %t30) + call void @fn_emit(ptr @.str932) + %t31 = load ptr, ptr %t24 + call void @fn_emit(ptr %t31) + call void @fn_emit(ptr @.str933) + br label %ifend2 +else1: + call void @fn_emit(ptr @.str934) + %t32 = load ptr, ptr %t12 + call void @fn_emit(ptr %t32) + call void @fn_emit(ptr @.str935) + %t33 = load ptr, ptr %t22 + call void @fn_emit(ptr %t33) + call void @fn_emit(ptr @.str936) + %t34 = load ptr, ptr %t26 + call void @fn_emit(ptr %t34) + call void @fn_emit(ptr @.str937) + br label %ifend2 +ifend2: + %t35 = load ptr, ptr %t22 + call void @fn_emit(ptr %t35) + call void @fn_emit(ptr @.str938) + store i32 0, ptr @g_g_term + %t36 = load ptr, ptr %t0 + %t37 = getelementptr inbounds %Str_Node, ptr %t36, i32 0, i32 5 + %t38 = load ptr, ptr %t37 + call void @fn_emit_block(ptr %t38) + %t39 = load i32, ptr @g_g_term + %t40 = icmp eq i32 %t39, 0 + %t41 = zext i1 %t40 to i32 + %t42 = icmp ne i32 %t41, 0 + br i1 %t42, label %then3, label %ifend5 +then3: + call void @fn_emit(ptr @.str939) + %t43 = load ptr, ptr %t26 + call void @fn_emit(ptr %t43) + call void @fn_emit(ptr @.str940) + br label %ifend5 +ifend5: + %t44 = load i32, ptr %t20 + %t45 = icmp ne i32 %t44, 0 + br i1 %t45, label %then6, label %ifend8 +then6: + %t46 = load ptr, ptr %t24 + call void @fn_emit(ptr %t46) + call void @fn_emit(ptr @.str941) + store i32 0, ptr @g_g_term + %t47 = load ptr, ptr %t0 + %t48 = getelementptr inbounds %Str_Node, ptr %t47, i32 0, i32 6 + %t49 = load ptr, ptr %t48 + %t50 = getelementptr inbounds %Str_Node, ptr %t49, i32 0, i32 0 + %t51 = load i32, ptr %t50 + %t52 = icmp eq i32 %t51, 12 + %t53 = zext i1 %t52 to i32 + %t54 = icmp ne i32 %t53, 0 + br i1 %t54, label %then9, label %else10 +then9: + %t55 = load ptr, ptr %t0 + %t56 = getelementptr inbounds %Str_Node, ptr %t55, i32 0, i32 6 + %t57 = load ptr, ptr %t56 + call void @fn_emit_stmt(ptr %t57) + br label %ifend11 +else10: + %t58 = load ptr, ptr %t0 + %t59 = getelementptr inbounds %Str_Node, ptr %t58, i32 0, i32 6 + %t60 = load ptr, ptr %t59 + call void @fn_emit_block(ptr %t60) + br label %ifend11 +ifend11: + %t61 = load i32, ptr @g_g_term + %t62 = icmp eq i32 %t61, 0 + %t63 = zext i1 %t62 to i32 + %t64 = icmp ne i32 %t63, 0 + br i1 %t64, label %then12, label %ifend14 +then12: + call void @fn_emit(ptr @.str942) + %t65 = load ptr, ptr %t26 + call void @fn_emit(ptr %t65) + call void @fn_emit(ptr @.str943) + br label %ifend14 +ifend14: + br label %ifend8 +ifend8: + %t66 = load ptr, ptr %t26 + call void @fn_emit(ptr %t66) + call void @fn_emit(ptr @.str944) + store i32 0, ptr @g_g_term + br label %ret +ret: + ret void +} + +define void @fn_emit_while(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t4 = alloca ptr + %t6 = alloca ptr + %t13 = alloca ptr + %t20 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = call ptr @fn_lbl(ptr @.str945) + store ptr %t1, ptr %t2 + %t3 = call ptr @fn_lbl(ptr @.str946) + store ptr %t3, ptr %t4 + %t5 = call ptr @fn_lbl(ptr @.str947) + store ptr %t5, ptr %t6 + call void @fn_emit(ptr @.str948) + %t7 = load ptr, ptr %t2 + call void @fn_emit(ptr %t7) + call void @fn_emit(ptr @.str949) + %t8 = load ptr, ptr %t2 + call void @fn_emit(ptr %t8) + call void @fn_emit(ptr @.str950) + %t9 = load ptr, ptr %t0 + %t10 = getelementptr inbounds %Str_Node, ptr %t9, i32 0, i32 4 + %t11 = load ptr, ptr %t10 + %t12 = call ptr @fn_emit_expr(ptr %t11) + store ptr %t12, ptr %t13 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %Str_Val, ptr %t14, i32 0, i32 0 + %t16 = load ptr, ptr %t15 + %t17 = call ptr @fn_sconcat(ptr %t16, ptr @.str952) + %t18 = call ptr @fn_sconcat(ptr @.str951, ptr %t17) + %t19 = call ptr @fn_emit_bind(ptr %t18) + store ptr %t19, ptr %t20 + call void @fn_emit(ptr @.str953) + %t21 = load ptr, ptr %t20 + call void @fn_emit(ptr %t21) + call void @fn_emit(ptr @.str954) + %t22 = load ptr, ptr %t4 + call void @fn_emit(ptr %t22) + call void @fn_emit(ptr @.str955) + %t23 = load ptr, ptr %t6 + call void @fn_emit(ptr %t23) + call void @fn_emit(ptr @.str956) + %t24 = load ptr, ptr %t4 + call void @fn_emit(ptr %t24) + call void @fn_emit(ptr @.str957) + store i32 0, ptr @g_g_term + %t25 = load ptr, ptr %t2 + %t26 = load ptr, ptr %t6 + call void @fn_loop_push(ptr %t25, ptr %t26) + %t27 = load ptr, ptr %t0 + %t28 = getelementptr inbounds %Str_Node, ptr %t27, i32 0, i32 5 + %t29 = load ptr, ptr %t28 + call void @fn_emit_block(ptr %t29) + call void @fn_loop_pop() + %t30 = load i32, ptr @g_g_term + %t31 = icmp eq i32 %t30, 0 + %t32 = zext i1 %t31 to i32 + %t33 = icmp ne i32 %t32, 0 + br i1 %t33, label %then0, label %ifend2 +then0: + call void @fn_emit(ptr @.str958) + %t34 = load ptr, ptr %t2 + call void @fn_emit(ptr %t34) + call void @fn_emit(ptr @.str959) + br label %ifend2 +ifend2: + %t35 = load ptr, ptr %t6 + call void @fn_emit(ptr %t35) + call void @fn_emit(ptr @.str960) + store i32 0, ptr @g_g_term + br label %ret +ret: + ret void +} + +define void @fn_emit_for(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t7 = alloca ptr + %t17 = alloca ptr + %t19 = alloca ptr + %t21 = alloca ptr + %t23 = alloca ptr + %t29 = alloca ptr + %t34 = alloca ptr + %t43 = alloca ptr + %t62 = alloca ptr + %t67 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = call ptr @fn_emit_alloca(ptr @.str961) + store ptr %t1, ptr %t2 + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 4 + %t5 = load ptr, ptr %t4 + %t6 = call ptr @fn_emit_expr(ptr %t5) + store ptr %t6, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds %Str_Val, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t9 + %t11 = load ptr, ptr %t2 + call void @fn_store_at(ptr @.str962, ptr %t10, ptr %t11) + %t12 = load ptr, ptr %t0 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 1 + %t14 = load ptr, ptr %t13 + %t15 = load ptr, ptr %t2 + call void @fn_loc_push(ptr %t14, ptr %t15, ptr @.str963) + %t16 = call ptr @fn_lbl(ptr @.str964) + store ptr %t16, ptr %t17 + %t18 = call ptr @fn_lbl(ptr @.str965) + store ptr %t18, ptr %t19 + %t20 = call ptr @fn_lbl(ptr @.str966) + store ptr %t20, ptr %t21 + %t22 = call ptr @fn_lbl(ptr @.str967) + store ptr %t22, ptr %t23 + call void @fn_emit(ptr @.str968) + %t24 = load ptr, ptr %t17 + call void @fn_emit(ptr %t24) + call void @fn_emit(ptr @.str969) + %t25 = load ptr, ptr %t17 + call void @fn_emit(ptr %t25) + call void @fn_emit(ptr @.str970) + %t26 = load ptr, ptr %t2 + %t27 = call ptr @fn_sconcat(ptr @.str971, ptr %t26) + %t28 = call ptr @fn_emit_bind(ptr %t27) + store ptr %t28, ptr %t29 + %t30 = load ptr, ptr %t0 + %t31 = getelementptr inbounds %Str_Node, ptr %t30, i32 0, i32 5 + %t32 = load ptr, ptr %t31 + %t33 = call ptr @fn_emit_expr(ptr %t32) + store ptr %t33, ptr %t34 + %t35 = load ptr, ptr %t29 + %t36 = load ptr, ptr %t34 + %t37 = getelementptr inbounds %Str_Val, ptr %t36, i32 0, i32 0 + %t38 = load ptr, ptr %t37 + %t39 = call ptr @fn_sconcat(ptr @.str973, ptr %t38) + %t40 = call ptr @fn_sconcat(ptr %t35, ptr %t39) + %t41 = call ptr @fn_sconcat(ptr @.str972, ptr %t40) + %t42 = call ptr @fn_emit_bind(ptr %t41) + store ptr %t42, ptr %t43 + call void @fn_emit(ptr @.str974) + %t44 = load ptr, ptr %t43 + call void @fn_emit(ptr %t44) + call void @fn_emit(ptr @.str975) + %t45 = load ptr, ptr %t19 + call void @fn_emit(ptr %t45) + call void @fn_emit(ptr @.str976) + %t46 = load ptr, ptr %t23 + call void @fn_emit(ptr %t46) + call void @fn_emit(ptr @.str977) + %t47 = load ptr, ptr %t19 + call void @fn_emit(ptr %t47) + call void @fn_emit(ptr @.str978) + store i32 0, ptr @g_g_term + %t48 = load ptr, ptr %t21 + %t49 = load ptr, ptr %t23 + call void @fn_loop_push(ptr %t48, ptr %t49) + %t50 = load ptr, ptr %t0 + %t51 = getelementptr inbounds %Str_Node, ptr %t50, i32 0, i32 6 + %t52 = load ptr, ptr %t51 + call void @fn_emit_block(ptr %t52) + call void @fn_loop_pop() + %t53 = load i32, ptr @g_g_term + %t54 = icmp eq i32 %t53, 0 + %t55 = zext i1 %t54 to i32 + %t56 = icmp ne i32 %t55, 0 + br i1 %t56, label %then0, label %ifend2 +then0: + call void @fn_emit(ptr @.str979) + %t57 = load ptr, ptr %t21 + call void @fn_emit(ptr %t57) + call void @fn_emit(ptr @.str980) + br label %ifend2 +ifend2: + %t58 = load ptr, ptr %t21 + call void @fn_emit(ptr %t58) + call void @fn_emit(ptr @.str981) + %t59 = load ptr, ptr %t2 + %t60 = call ptr @fn_sconcat(ptr @.str982, ptr %t59) + %t61 = call ptr @fn_emit_bind(ptr %t60) + store ptr %t61, ptr %t62 + %t63 = load ptr, ptr %t62 + %t64 = call ptr @fn_sconcat(ptr %t63, ptr @.str984) + %t65 = call ptr @fn_sconcat(ptr @.str983, ptr %t64) + %t66 = call ptr @fn_emit_bind(ptr %t65) + store ptr %t66, ptr %t67 + %t68 = load ptr, ptr %t67 + %t69 = load ptr, ptr %t2 + call void @fn_store_at(ptr @.str985, ptr %t68, ptr %t69) + call void @fn_emit(ptr @.str986) + %t70 = load ptr, ptr %t17 + call void @fn_emit(ptr %t70) + call void @fn_emit(ptr @.str987) + %t71 = load ptr, ptr %t23 + call void @fn_emit(ptr %t71) + call void @fn_emit(ptr @.str988) + store i32 0, ptr @g_g_term + br label %ret +ret: + ret void +} + +define void @fn_emit_return(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t13 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = icmp eq ptr %t3, null + %t5 = zext i1 %t4 to i32 + %t6 = icmp eq i32 %t5, 0 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %then0, label %ifend2 +then0: + %t9 = load ptr, ptr %t0 + %t10 = getelementptr inbounds %Str_Node, ptr %t9, i32 0, i32 4 + %t11 = load ptr, ptr %t10 + %t12 = call ptr @fn_emit_expr(ptr %t11) + store ptr %t12, ptr %t13 + %t14 = load ptr, ptr @g_ret_ty + %t15 = call ptr @fn_llty(ptr %t14) + %t16 = load ptr, ptr %t13 + %t17 = getelementptr inbounds %Str_Val, ptr %t16, i32 0, i32 0 + %t18 = load ptr, ptr %t17 + call void @fn_store_at(ptr %t15, ptr %t18, ptr @.str989) + br label %ifend2 +ifend2: + call void @fn_emit(ptr @.str990) + store i32 1, ptr @g_g_term + br label %ret +ret: + ret void +} + +define i32 @fn_arm_is_default(ptr %arg_arm) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t11 = alloca i32 + store ptr %arg_arm, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 7 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds %LSlice, ptr %t5, i32 0, i32 1 + %t7 = load i32, ptr %t6 + %t8 = icmp slt i32 %t2, %t7 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t12 = load ptr, ptr %t0 + %t13 = getelementptr inbounds %Str_Node, ptr %t12, i32 0, i32 7 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 0 + %t16 = load ptr, ptr %t15 + %t17 = load i32, ptr %t1 + %t18 = getelementptr inbounds ptr, ptr %t16, i32 %t17 + %t19 = load ptr, ptr %t18 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 0 + %t21 = load i32, ptr %t20 + %t22 = icmp eq i32 %t21, 33 + %t23 = zext i1 %t22 to i32 + %t24 = icmp ne i32 %t23, 0 + %t25 = zext i1 %t24 to i32 + store i32 %t25, ptr %t11 + br i1 %t24, label %sc3, label %scend4 +sc3: + %t26 = load ptr, ptr %t0 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 7 + %t28 = load ptr, ptr %t27 + %t29 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 0 + %t30 = load ptr, ptr %t29 + %t31 = load i32, ptr %t1 + %t32 = getelementptr inbounds ptr, ptr %t30, i32 %t31 + %t33 = load ptr, ptr %t32 + %t34 = getelementptr inbounds %Str_Node, ptr %t33, i32 0, i32 1 + %t35 = load ptr, ptr %t34 + %t36 = call i32 @fn_streq(ptr %t35, ptr @.str991) + %t37 = icmp ne i32 %t36, 0 + %t38 = zext i1 %t37 to i32 + store i32 %t38, ptr %t11 + br label %scend4 +scend4: + %t39 = load i32, ptr %t11 + %t40 = icmp ne i32 %t39, 0 + br i1 %t40, label %then5, label %ifend7 +then5: + store i32 1, ptr %retval + br label %ret +ifend7: + %t41 = load i32, ptr %t1 + %t42 = add i32 %t41, 1 + store i32 %t42, ptr %t1 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t43 = load i32, ptr %retval + ret i32 %t43 +} + +define void @fn_emit_match(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t5 = alloca ptr + %t7 = alloca ptr + %t8 = alloca ptr + %t9 = alloca i32 + %t27 = alloca ptr + %t32 = alloca ptr + %t33 = alloca i32 + %t34 = alloca i32 + %t53 = alloca ptr + %t64 = alloca ptr + %t77 = alloca ptr + %t79 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_emit_expr(ptr %t3) + store ptr %t4, ptr %t5 + %t6 = call ptr @fn_lbl(ptr @.str992) + store ptr %t6, ptr %t7 + store ptr null, ptr %t8 + store i32 0, ptr %t9 + br label %wcond0 +wcond0: + %t10 = load i32, ptr %t9 + %t11 = load ptr, ptr %t0 + %t12 = getelementptr inbounds %Str_Node, ptr %t11, i32 0, i32 7 + %t13 = load ptr, ptr %t12 + %t14 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 1 + %t15 = load i32, ptr %t14 + %t16 = icmp slt i32 %t10, %t15 + %t17 = zext i1 %t16 to i32 + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %wbody1, label %wend2 +wbody1: + %t19 = load ptr, ptr %t0 + %t20 = getelementptr inbounds %Str_Node, ptr %t19, i32 0, i32 7 + %t21 = load ptr, ptr %t20 + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 0 + %t23 = load ptr, ptr %t22 + %t24 = load i32, ptr %t9 + %t25 = getelementptr inbounds ptr, ptr %t23, i32 %t24 + %t26 = load ptr, ptr %t25 + store ptr %t26, ptr %t27 + %t28 = load ptr, ptr %t27 + %t29 = call i32 @fn_arm_is_default(ptr %t28) + %t30 = icmp ne i32 %t29, 0 + br i1 %t30, label %then3, label %else4 +then3: + %t31 = load ptr, ptr %t27 + store ptr %t31, ptr %t8 + br label %ifend5 +else4: + store ptr @.str993, ptr %t32 + store i32 1, ptr %t33 + store i32 0, ptr %t34 + br label %wcond6 +wcond6: + %t35 = load i32, ptr %t34 + %t36 = load ptr, ptr %t27 + %t37 = getelementptr inbounds %Str_Node, ptr %t36, i32 0, i32 7 + %t38 = load ptr, ptr %t37 + %t39 = getelementptr inbounds %LSlice, ptr %t38, i32 0, i32 1 + %t40 = load i32, ptr %t39 + %t41 = icmp slt i32 %t35, %t40 + %t42 = zext i1 %t41 to i32 + %t43 = icmp ne i32 %t42, 0 + br i1 %t43, label %wbody7, label %wend8 +wbody7: + %t44 = load ptr, ptr %t27 + %t45 = getelementptr inbounds %Str_Node, ptr %t44, i32 0, i32 7 + %t46 = load ptr, ptr %t45 + %t47 = getelementptr inbounds %LSlice, ptr %t46, i32 0, i32 0 + %t48 = load ptr, ptr %t47 + %t49 = load i32, ptr %t34 + %t50 = getelementptr inbounds ptr, ptr %t48, i32 %t49 + %t51 = load ptr, ptr %t50 + %t52 = call ptr @fn_emit_expr(ptr %t51) + store ptr %t52, ptr %t53 + %t54 = load ptr, ptr %t5 + %t55 = getelementptr inbounds %Str_Val, ptr %t54, i32 0, i32 0 + %t56 = load ptr, ptr %t55 + %t57 = load ptr, ptr %t53 + %t58 = getelementptr inbounds %Str_Val, ptr %t57, i32 0, i32 0 + %t59 = load ptr, ptr %t58 + %t60 = call ptr @fn_sconcat(ptr @.str995, ptr %t59) + %t61 = call ptr @fn_sconcat(ptr %t56, ptr %t60) + %t62 = call ptr @fn_sconcat(ptr @.str994, ptr %t61) + %t63 = call ptr @fn_emit_bind(ptr %t62) + store ptr %t63, ptr %t64 + %t65 = load i32, ptr %t33 + %t66 = icmp ne i32 %t65, 0 + br i1 %t66, label %then9, label %else10 +then9: + %t67 = load ptr, ptr %t64 + store ptr %t67, ptr %t32 + store i32 0, ptr %t33 + br label %ifend11 +else10: + %t68 = load ptr, ptr %t32 + %t69 = load ptr, ptr %t64 + %t70 = call ptr @fn_sconcat(ptr @.str997, ptr %t69) + %t71 = call ptr @fn_sconcat(ptr %t68, ptr %t70) + %t72 = call ptr @fn_sconcat(ptr @.str996, ptr %t71) + %t73 = call ptr @fn_emit_bind(ptr %t72) + store ptr %t73, ptr %t32 + br label %ifend11 +ifend11: + %t74 = load i32, ptr %t34 + %t75 = add i32 %t74, 1 + store i32 %t75, ptr %t34 + br label %wcond6 +wend8: + %t76 = call ptr @fn_lbl(ptr @.str998) + store ptr %t76, ptr %t77 + %t78 = call ptr @fn_lbl(ptr @.str999) + store ptr %t78, ptr %t79 + call void @fn_emit(ptr @.str1000) + %t80 = load ptr, ptr %t32 + call void @fn_emit(ptr %t80) + call void @fn_emit(ptr @.str1001) + %t81 = load ptr, ptr %t77 + call void @fn_emit(ptr %t81) + call void @fn_emit(ptr @.str1002) + %t82 = load ptr, ptr %t79 + call void @fn_emit(ptr %t82) + call void @fn_emit(ptr @.str1003) + %t83 = load ptr, ptr %t77 + call void @fn_emit(ptr %t83) + call void @fn_emit(ptr @.str1004) + store i32 0, ptr @g_g_term + %t84 = load ptr, ptr %t27 + %t85 = getelementptr inbounds %Str_Node, ptr %t84, i32 0, i32 4 + %t86 = load ptr, ptr %t85 + call void @fn_emit_block(ptr %t86) + %t87 = load i32, ptr @g_g_term + %t88 = icmp eq i32 %t87, 0 + %t89 = zext i1 %t88 to i32 + %t90 = icmp ne i32 %t89, 0 + br i1 %t90, label %then12, label %ifend14 +then12: + call void @fn_emit(ptr @.str1005) + %t91 = load ptr, ptr %t7 + call void @fn_emit(ptr %t91) + call void @fn_emit(ptr @.str1006) + br label %ifend14 +ifend14: + %t92 = load ptr, ptr %t79 + call void @fn_emit(ptr %t92) + call void @fn_emit(ptr @.str1007) + store i32 0, ptr @g_g_term + br label %ifend5 +ifend5: + %t93 = load i32, ptr %t9 + %t94 = add i32 %t93, 1 + store i32 %t94, ptr %t9 + br label %wcond0 +wend2: + %t95 = load ptr, ptr %t8 + %t96 = icmp eq ptr %t95, null + %t97 = zext i1 %t96 to i32 + %t98 = icmp eq i32 %t97, 0 + %t99 = zext i1 %t98 to i32 + %t100 = icmp ne i32 %t99, 0 + br i1 %t100, label %then15, label %ifend17 +then15: + %t101 = load ptr, ptr %t8 + %t102 = getelementptr inbounds %Str_Node, ptr %t101, i32 0, i32 4 + %t103 = load ptr, ptr %t102 + call void @fn_emit_block(ptr %t103) + br label %ifend17 +ifend17: + %t104 = load i32, ptr @g_g_term + %t105 = icmp eq i32 %t104, 0 + %t106 = zext i1 %t105 to i32 + %t107 = icmp ne i32 %t106, 0 + br i1 %t107, label %then18, label %ifend20 +then18: + call void @fn_emit(ptr @.str1008) + %t108 = load ptr, ptr %t7 + call void @fn_emit(ptr %t108) + call void @fn_emit(ptr @.str1009) + br label %ifend20 +ifend20: + %t109 = load ptr, ptr %t7 + call void @fn_emit(ptr %t109) + call void @fn_emit(ptr @.str1010) + store i32 0, ptr @g_g_term + br label %ret +ret: + ret void +} + +define void @fn_emit_stmt(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t10 = alloca ptr + %t19 = alloca ptr + %t26 = alloca ptr + %t41 = alloca ptr + %t48 = alloca ptr + %t61 = alloca ptr + %t186 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 0 + %t3 = load i32, ptr %t2 + %t4 = icmp eq i32 %t3, 10 + %t5 = zext i1 %t4 to i32 + %t6 = icmp ne i32 %t5, 0 + br i1 %t6, label %then0, label %ifend2 +then0: + %t7 = load ptr, ptr %t0 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 3 + %t9 = load ptr, ptr %t8 + store ptr %t9, ptr %t10 + %t11 = load ptr, ptr %t10 + %t12 = icmp eq ptr %t11, null + %t13 = zext i1 %t12 to i32 + %t14 = icmp ne i32 %t13, 0 + br i1 %t14, label %then3, label %ifend5 +then3: + %t15 = load ptr, ptr %t0 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 4 + %t17 = load ptr, ptr %t16 + %t18 = call ptr @fn_emit_expr(ptr %t17) + store ptr %t18, ptr %t19 + %t20 = load ptr, ptr %t19 + %t21 = getelementptr inbounds %Str_Val, ptr %t20, i32 0, i32 1 + %t22 = load ptr, ptr %t21 + store ptr %t22, ptr %t10 + %t23 = load ptr, ptr %t10 + %t24 = call ptr @fn_llty(ptr %t23) + %t25 = call ptr @fn_emit_alloca(ptr %t24) + store ptr %t25, ptr %t26 + %t27 = load ptr, ptr %t10 + %t28 = call ptr @fn_llty(ptr %t27) + %t29 = load ptr, ptr %t19 + %t30 = getelementptr inbounds %Str_Val, ptr %t29, i32 0, i32 0 + %t31 = load ptr, ptr %t30 + %t32 = load ptr, ptr %t26 + call void @fn_store_at(ptr %t28, ptr %t31, ptr %t32) + %t33 = load ptr, ptr %t0 + %t34 = getelementptr inbounds %Str_Node, ptr %t33, i32 0, i32 1 + %t35 = load ptr, ptr %t34 + %t36 = load ptr, ptr %t26 + %t37 = load ptr, ptr %t10 + call void @fn_loc_push(ptr %t35, ptr %t36, ptr %t37) + br label %ret +ifend5: + %t38 = load ptr, ptr %t10 + %t39 = call ptr @fn_llty(ptr %t38) + %t40 = call ptr @fn_emit_alloca(ptr %t39) + store ptr %t40, ptr %t41 + %t42 = load ptr, ptr %t0 + %t43 = getelementptr inbounds %Str_Node, ptr %t42, i32 0, i32 4 + %t44 = load ptr, ptr %t43 + %t45 = icmp eq ptr %t44, null + %t46 = zext i1 %t45 to i32 + %t47 = icmp ne i32 %t46, 0 + br i1 %t47, label %then6, label %else7 +then6: + store ptr @.str1011, ptr %t48 + %t49 = load ptr, ptr %t10 + %t50 = call ptr @fn_llty(ptr %t49) + %t51 = call i32 @fn_streq(ptr %t50, ptr @.str1012) + %t52 = icmp ne i32 %t51, 0 + br i1 %t52, label %then9, label %ifend11 +then9: + store ptr @.str1013, ptr %t48 + br label %ifend11 +ifend11: + %t53 = load ptr, ptr %t10 + %t54 = call ptr @fn_llty(ptr %t53) + %t55 = load ptr, ptr %t48 + %t56 = load ptr, ptr %t41 + call void @fn_store_at(ptr %t54, ptr %t55, ptr %t56) + br label %ifend8 +else7: + %t57 = load ptr, ptr %t0 + %t58 = getelementptr inbounds %Str_Node, ptr %t57, i32 0, i32 4 + %t59 = load ptr, ptr %t58 + %t60 = call ptr @fn_emit_expr(ptr %t59) + store ptr %t60, ptr %t61 + %t62 = load ptr, ptr %t10 + %t63 = call ptr @fn_llty(ptr %t62) + %t64 = load ptr, ptr %t61 + %t65 = getelementptr inbounds %Str_Val, ptr %t64, i32 0, i32 0 + %t66 = load ptr, ptr %t65 + %t67 = load ptr, ptr %t41 + call void @fn_store_at(ptr %t63, ptr %t66, ptr %t67) + br label %ifend8 +ifend8: + %t68 = load ptr, ptr %t0 + %t69 = getelementptr inbounds %Str_Node, ptr %t68, i32 0, i32 1 + %t70 = load ptr, ptr %t69 + %t71 = load ptr, ptr %t41 + %t72 = load ptr, ptr %t10 + call void @fn_loc_push(ptr %t70, ptr %t71, ptr %t72) + br label %ret +ifend2: + %t73 = load ptr, ptr %t0 + %t74 = getelementptr inbounds %Str_Node, ptr %t73, i32 0, i32 0 + %t75 = load i32, ptr %t74 + %t76 = icmp eq i32 %t75, 11 + %t77 = zext i1 %t76 to i32 + %t78 = icmp ne i32 %t77, 0 + br i1 %t78, label %then12, label %ifend14 +then12: + %t79 = load ptr, ptr %t0 + call void @fn_emit_assign(ptr %t79) + br label %ret +ifend14: + %t80 = load ptr, ptr %t0 + %t81 = getelementptr inbounds %Str_Node, ptr %t80, i32 0, i32 0 + %t82 = load i32, ptr %t81 + %t83 = icmp eq i32 %t82, 12 + %t84 = zext i1 %t83 to i32 + %t85 = icmp ne i32 %t84, 0 + br i1 %t85, label %then15, label %ifend17 +then15: + %t86 = load ptr, ptr %t0 + call void @fn_emit_if(ptr %t86) + br label %ret +ifend17: + %t87 = load ptr, ptr %t0 + %t88 = getelementptr inbounds %Str_Node, ptr %t87, i32 0, i32 0 + %t89 = load i32, ptr %t88 + %t90 = icmp eq i32 %t89, 13 + %t91 = zext i1 %t90 to i32 + %t92 = icmp ne i32 %t91, 0 + br i1 %t92, label %then18, label %ifend20 +then18: + %t93 = load ptr, ptr %t0 + call void @fn_emit_while(ptr %t93) + br label %ret +ifend20: + %t94 = load ptr, ptr %t0 + %t95 = getelementptr inbounds %Str_Node, ptr %t94, i32 0, i32 0 + %t96 = load i32, ptr %t95 + %t97 = icmp eq i32 %t96, 14 + %t98 = zext i1 %t97 to i32 + %t99 = icmp ne i32 %t98, 0 + br i1 %t99, label %then21, label %ifend23 +then21: + %t100 = load ptr, ptr %t0 + call void @fn_emit_for(ptr %t100) + br label %ret +ifend23: + %t101 = load ptr, ptr %t0 + %t102 = getelementptr inbounds %Str_Node, ptr %t101, i32 0, i32 0 + %t103 = load i32, ptr %t102 + %t104 = icmp eq i32 %t103, 15 + %t105 = zext i1 %t104 to i32 + %t106 = icmp ne i32 %t105, 0 + br i1 %t106, label %then24, label %ifend26 +then24: + %t107 = load ptr, ptr %t0 + call void @fn_emit_return(ptr %t107) + br label %ret +ifend26: + %t108 = load ptr, ptr %t0 + %t109 = getelementptr inbounds %Str_Node, ptr %t108, i32 0, i32 0 + %t110 = load i32, ptr %t109 + %t111 = icmp eq i32 %t110, 17 + %t112 = zext i1 %t111 to i32 + %t113 = icmp ne i32 %t112, 0 + br i1 %t113, label %then27, label %ifend29 +then27: + call void @fn_emit(ptr @.str1014) + %t114 = load ptr, ptr @g_brk_lbl + %t115 = getelementptr inbounds %LSlice, ptr %t114, i32 0, i32 0 + %t116 = load ptr, ptr %t115 + %t117 = load i32, ptr @g_nloop + %t118 = sub i32 %t117, 1 + %t119 = getelementptr inbounds ptr, ptr %t116, i32 %t118 + %t120 = load ptr, ptr %t119 + call void @fn_emit(ptr %t120) + call void @fn_emit(ptr @.str1015) + store i32 1, ptr @g_g_term + br label %ret +ifend29: + %t121 = load ptr, ptr %t0 + %t122 = getelementptr inbounds %Str_Node, ptr %t121, i32 0, i32 0 + %t123 = load i32, ptr %t122 + %t124 = icmp eq i32 %t123, 18 + %t125 = zext i1 %t124 to i32 + %t126 = icmp ne i32 %t125, 0 + br i1 %t126, label %then30, label %ifend32 +then30: + call void @fn_emit(ptr @.str1016) + %t127 = load ptr, ptr @g_cnt_lbl + %t128 = getelementptr inbounds %LSlice, ptr %t127, i32 0, i32 0 + %t129 = load ptr, ptr %t128 + %t130 = load i32, ptr @g_nloop + %t131 = sub i32 %t130, 1 + %t132 = getelementptr inbounds ptr, ptr %t129, i32 %t131 + %t133 = load ptr, ptr %t132 + call void @fn_emit(ptr %t133) + call void @fn_emit(ptr @.str1017) + store i32 1, ptr @g_g_term + br label %ret +ifend32: + %t134 = load ptr, ptr %t0 + %t135 = getelementptr inbounds %Str_Node, ptr %t134, i32 0, i32 0 + %t136 = load i32, ptr %t135 + %t137 = icmp eq i32 %t136, 19 + %t138 = zext i1 %t137 to i32 + %t139 = icmp ne i32 %t138, 0 + br i1 %t139, label %then33, label %ifend35 +then33: + %t140 = load ptr, ptr %t0 + call void @fn_emit_match(ptr %t140) + br label %ret +ifend35: + %t141 = load ptr, ptr %t0 + %t142 = getelementptr inbounds %Str_Node, ptr %t141, i32 0, i32 0 + %t143 = load i32, ptr %t142 + %t144 = icmp eq i32 %t143, 21 + %t145 = zext i1 %t144 to i32 + %t146 = icmp ne i32 %t145, 0 + br i1 %t146, label %then36, label %ifend38 +then36: + %t147 = load ptr, ptr %t0 + call void @fn_emit_query(ptr %t147) + br label %ret +ifend38: + %t148 = load ptr, ptr %t0 + %t149 = getelementptr inbounds %Str_Node, ptr %t148, i32 0, i32 0 + %t150 = load i32, ptr %t149 + %t151 = icmp eq i32 %t150, 22 + %t152 = zext i1 %t151 to i32 + %t153 = icmp ne i32 %t152, 0 + br i1 %t153, label %then39, label %ifend41 +then39: + %t154 = load ptr, ptr %t0 + call void @fn_emit_spawn(ptr %t154) + br label %ret +ifend41: + %t155 = load ptr, ptr %t0 + %t156 = getelementptr inbounds %Str_Node, ptr %t155, i32 0, i32 0 + %t157 = load i32, ptr %t156 + %t158 = icmp eq i32 %t157, 23 + %t159 = zext i1 %t158 to i32 + %t160 = icmp ne i32 %t159, 0 + br i1 %t160, label %then42, label %ifend44 +then42: + %t161 = load ptr, ptr %t0 + call void @fn_emit_despawn(ptr %t161) + br label %ret +ifend44: + %t162 = load ptr, ptr %t0 + %t163 = getelementptr inbounds %Str_Node, ptr %t162, i32 0, i32 0 + %t164 = load i32, ptr %t163 + %t165 = icmp eq i32 %t164, 24 + %t166 = zext i1 %t165 to i32 + %t167 = icmp ne i32 %t166, 0 + br i1 %t167, label %then45, label %ifend47 +then45: + %t168 = load ptr, ptr %t0 + call void @fn_emit_machine(ptr %t168) + br label %ret +ifend47: + %t169 = load ptr, ptr %t0 + %t170 = getelementptr inbounds %Str_Node, ptr %t169, i32 0, i32 0 + %t171 = load i32, ptr %t170 + %t172 = icmp eq i32 %t171, 26 + %t173 = zext i1 %t172 to i32 + %t174 = icmp ne i32 %t173, 0 + br i1 %t174, label %then48, label %ifend50 +then48: + %t175 = load ptr, ptr %t0 + call void @fn_emit_become(ptr %t175) + br label %ret +ifend50: + %t176 = load ptr, ptr %t0 + %t177 = getelementptr inbounds %Str_Node, ptr %t176, i32 0, i32 0 + %t178 = load i32, ptr %t177 + %t179 = icmp eq i32 %t178, 16 + %t180 = zext i1 %t179 to i32 + %t181 = icmp ne i32 %t180, 0 + br i1 %t181, label %then51, label %ifend53 +then51: + %t182 = load ptr, ptr %t0 + %t183 = getelementptr inbounds %Str_Node, ptr %t182, i32 0, i32 4 + %t184 = load ptr, ptr %t183 + %t185 = call ptr @fn_emit_expr(ptr %t184) + store ptr %t185, ptr %t186 + br label %ret +ifend53: + call void @fn_perr(ptr @.str1018) + br label %ret +ret: + ret void +} + +define void @fn_loop_push(ptr %arg_cont, ptr %arg_brk) { +entry: + %t0 = alloca ptr + %t1 = alloca ptr + store ptr %arg_cont, ptr %t0 + store ptr %arg_brk, ptr %t1 + %t2 = load i32, ptr @g_nloop + %t3 = load ptr, ptr @g_cnt_lbl + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %then0, label %else1 +then0: + %t9 = load ptr, ptr @g_cnt_lbl + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr @g_nloop + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t0 + store ptr %t14, ptr %t13 + %t15 = load ptr, ptr @g_brk_lbl + %t16 = getelementptr inbounds %LSlice, ptr %t15, i32 0, i32 0 + %t17 = load ptr, ptr %t16 + %t18 = load i32, ptr @g_nloop + %t19 = getelementptr inbounds ptr, ptr %t17, i32 %t18 + %t20 = load ptr, ptr %t1 + store ptr %t20, ptr %t19 + br label %ifend2 +else1: + %t21 = load ptr, ptr @g_cnt_lbl + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 1 + %t23 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 2 + %t24 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 0 + %t25 = load i32, ptr %t22 + %t26 = load i32, ptr %t23 + %t27 = icmp sge i32 %t25, %t26 + br i1 %t27, label %grow3, label %put4 +grow3: + %t28 = mul i32 %t26, 2 + %t29 = icmp eq i32 %t26, 0 + %t30 = select i1 %t29, i32 8, i32 %t28 + %t31 = getelementptr ptr, ptr null, i32 1 + %t32 = ptrtoint ptr %t31 to i64 + %t33 = zext i32 %t30 to i64 + %t34 = mul i64 %t33, %t32 + %t35 = load ptr, ptr %t24 + %t36 = call ptr @realloc(ptr %t35, i64 %t34) + store ptr %t36, ptr %t24 + store i32 %t30, ptr %t23 + br label %put4 +put4: + %t37 = load ptr, ptr %t0 + %t38 = load ptr, ptr %t24 + %t39 = getelementptr inbounds ptr, ptr %t38, i32 %t25 + store ptr %t37, ptr %t39 + %t40 = add i32 %t25, 1 + store i32 %t40, ptr %t22 + %t41 = load ptr, ptr @g_brk_lbl + %t42 = getelementptr inbounds %LSlice, ptr %t41, i32 0, i32 1 + %t43 = getelementptr inbounds %LSlice, ptr %t41, i32 0, i32 2 + %t44 = getelementptr inbounds %LSlice, ptr %t41, i32 0, i32 0 + %t45 = load i32, ptr %t42 + %t46 = load i32, ptr %t43 + %t47 = icmp sge i32 %t45, %t46 + br i1 %t47, label %grow5, label %put6 +grow5: + %t48 = mul i32 %t46, 2 + %t49 = icmp eq i32 %t46, 0 + %t50 = select i1 %t49, i32 8, i32 %t48 + %t51 = getelementptr ptr, ptr null, i32 1 + %t52 = ptrtoint ptr %t51 to i64 + %t53 = zext i32 %t50 to i64 + %t54 = mul i64 %t53, %t52 + %t55 = load ptr, ptr %t44 + %t56 = call ptr @realloc(ptr %t55, i64 %t54) + store ptr %t56, ptr %t44 + store i32 %t50, ptr %t43 + br label %put6 +put6: + %t57 = load ptr, ptr %t1 + %t58 = load ptr, ptr %t44 + %t59 = getelementptr inbounds ptr, ptr %t58, i32 %t45 + store ptr %t57, ptr %t59 + %t60 = add i32 %t45, 1 + store i32 %t60, ptr %t42 + br label %ifend2 +ifend2: + %t61 = load i32, ptr @g_nloop + %t62 = add i32 %t61, 1 + store i32 %t62, ptr @g_nloop + br label %ret +ret: + ret void +} + +define void @fn_loop_pop() { +entry: + %t0 = load i32, ptr @g_nloop + %t1 = sub i32 %t0, 1 + store i32 %t1, ptr @g_nloop + br label %ret +ret: + ret void +} + +define i32 @fn_has_ecs() { +entry: + %retval = alloca i32 + %t0 = alloca i32 + %t16 = alloca i32 + %t17 = alloca i32 + store i32 0, ptr %t0 + br label %wcond0 +wcond0: + %t1 = load i32, ptr %t0 + %t2 = load ptr, ptr @g_prog + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + %t4 = load i32, ptr %t3 + %t5 = icmp slt i32 %t1, %t4 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + %t8 = load ptr, ptr @g_prog + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t9 + %t11 = load i32, ptr %t0 + %t12 = getelementptr inbounds ptr, ptr %t10, i32 %t11 + %t13 = load ptr, ptr %t12 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 0 + %t15 = load i32, ptr %t14 + store i32 %t15, ptr %t16 + %t18 = load i32, ptr %t16 + %t19 = icmp eq i32 %t18, 8 + %t20 = zext i1 %t19 to i32 + %t21 = icmp ne i32 %t20, 0 + %t22 = zext i1 %t21 to i32 + store i32 %t22, ptr %t17 + br i1 %t21, label %scend4, label %sc3 +sc3: + %t23 = load i32, ptr %t16 + %t24 = icmp eq i32 %t23, 9 + %t25 = zext i1 %t24 to i32 + %t26 = icmp ne i32 %t25, 0 + %t27 = zext i1 %t26 to i32 + store i32 %t27, ptr %t17 + br label %scend4 +scend4: + %t28 = load i32, ptr %t17 + %t29 = icmp ne i32 %t28, 0 + br i1 %t29, label %then5, label %ifend7 +then5: + store i32 1, ptr %retval + br label %ret +ifend7: + %t30 = load i32, ptr %t0 + %t31 = add i32 %t30, 1 + store i32 %t31, ptr %t0 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t32 = load i32, ptr %retval + ret i32 %t32 +} + +define i32 @fn_has_systems() { +entry: + %retval = alloca i32 + %t0 = alloca i32 + store i32 0, ptr %t0 + br label %wcond0 +wcond0: + %t1 = load i32, ptr %t0 + %t2 = load ptr, ptr @g_prog + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + %t4 = load i32, ptr %t3 + %t5 = icmp slt i32 %t1, %t4 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + %t8 = load ptr, ptr @g_prog + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t9 + %t11 = load i32, ptr %t0 + %t12 = getelementptr inbounds ptr, ptr %t10, i32 %t11 + %t13 = load ptr, ptr %t12 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 0 + %t15 = load i32, ptr %t14 + %t16 = icmp eq i32 %t15, 9 + %t17 = zext i1 %t16 to i32 + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %then3, label %ifend5 +then3: + store i32 1, ptr %retval + br label %ret +ifend5: + %t19 = load i32, ptr %t0 + %t20 = add i32 %t19, 1 + store i32 %t20, ptr %t0 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t21 = load i32, ptr %retval + ret i32 %t21 +} + +define void @fn_emit_ecs_storage() { +entry: + %t1 = alloca ptr + %t11 = alloca i32 + %t25 = alloca ptr + %t45 = alloca i32 + call void @fn_emith(ptr @.str1019) + call void @fn_emith(ptr @.str1020) + call void @fn_emith(ptr @.str1021) + %t0 = call ptr @fn_itoa(i32 1024) + store ptr %t0, ptr %t1 + %t2 = load ptr, ptr %t1 + %t3 = call ptr @fn_sconcat(ptr %t2, ptr @.str1023) + %t4 = call ptr @fn_sconcat(ptr @.str1022, ptr %t3) + call void @fn_emith(ptr %t4) + %t5 = load ptr, ptr %t1 + %t6 = call ptr @fn_sconcat(ptr %t5, ptr @.str1025) + %t7 = call ptr @fn_sconcat(ptr @.str1024, ptr %t6) + call void @fn_emith(ptr %t7) + %t8 = load ptr, ptr %t1 + %t9 = call ptr @fn_sconcat(ptr %t8, ptr @.str1027) + %t10 = call ptr @fn_sconcat(ptr @.str1026, ptr %t9) + call void @fn_emith(ptr %t10) + call void @fn_emith(ptr @.str1028) + store i32 0, ptr %t11 + br label %wcond0 +wcond0: + %t12 = load i32, ptr %t11 + %t13 = load ptr, ptr @g_prog + %t14 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 1 + %t15 = load i32, ptr %t14 + %t16 = icmp slt i32 %t12, %t15 + %t17 = zext i1 %t16 to i32 + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %wbody1, label %wend2 +wbody1: + %t19 = load ptr, ptr @g_prog + %t20 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 0 + %t21 = load ptr, ptr %t20 + %t22 = load i32, ptr %t11 + %t23 = getelementptr inbounds ptr, ptr %t21, i32 %t22 + %t24 = load ptr, ptr %t23 + store ptr %t24, ptr %t25 + %t26 = load ptr, ptr %t25 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 0 + %t28 = load i32, ptr %t27 + %t29 = icmp eq i32 %t28, 8 + %t30 = zext i1 %t29 to i32 + %t31 = icmp ne i32 %t30, 0 + br i1 %t31, label %then3, label %ifend5 +then3: + %t32 = load ptr, ptr %t25 + %t33 = getelementptr inbounds %Str_Node, ptr %t32, i32 0, i32 1 + %t34 = load ptr, ptr %t33 + %t35 = call ptr @fn_sconcat(ptr %t34, ptr @.str1030) + %t36 = call ptr @fn_sconcat(ptr @.str1029, ptr %t35) + call void @fn_emith(ptr %t36) + %t37 = load ptr, ptr %t25 + %t38 = getelementptr inbounds %Str_Node, ptr %t37, i32 0, i32 7 + %t39 = load ptr, ptr %t38 + %t40 = getelementptr inbounds %LSlice, ptr %t39, i32 0, i32 1 + %t41 = load i32, ptr %t40 + %t42 = icmp eq i32 %t41, 0 + %t43 = zext i1 %t42 to i32 + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then6, label %ifend8 +then6: + call void @fn_emith(ptr @.str1031) + br label %ifend8 +ifend8: + store i32 0, ptr %t45 + br label %wcond9 +wcond9: + %t46 = load i32, ptr %t45 + %t47 = load ptr, ptr %t25 + %t48 = getelementptr inbounds %Str_Node, ptr %t47, i32 0, i32 7 + %t49 = load ptr, ptr %t48 + %t50 = getelementptr inbounds %LSlice, ptr %t49, i32 0, i32 1 + %t51 = load i32, ptr %t50 + %t52 = icmp slt i32 %t46, %t51 + %t53 = zext i1 %t52 to i32 + %t54 = icmp ne i32 %t53, 0 + br i1 %t54, label %wbody10, label %wend11 +wbody10: + %t55 = load i32, ptr %t45 + %t56 = icmp sgt i32 %t55, 0 + %t57 = zext i1 %t56 to i32 + %t58 = icmp ne i32 %t57, 0 + br i1 %t58, label %then12, label %ifend14 +then12: + call void @fn_emith(ptr @.str1032) + br label %ifend14 +ifend14: + %t59 = load ptr, ptr %t25 + %t60 = getelementptr inbounds %Str_Node, ptr %t59, i32 0, i32 7 + %t61 = load ptr, ptr %t60 + %t62 = getelementptr inbounds %LSlice, ptr %t61, i32 0, i32 0 + %t63 = load ptr, ptr %t62 + %t64 = load i32, ptr %t45 + %t65 = getelementptr inbounds ptr, ptr %t63, i32 %t64 + %t66 = load ptr, ptr %t65 + %t67 = getelementptr inbounds %Str_Node, ptr %t66, i32 0, i32 3 + %t68 = load ptr, ptr %t67 + %t69 = call ptr @fn_llty(ptr %t68) + call void @fn_emith(ptr %t69) + %t70 = load i32, ptr %t45 + %t71 = add i32 %t70, 1 + store i32 %t71, ptr %t45 + br label %wcond9 +wend11: + call void @fn_emith(ptr @.str1033) + %t72 = load ptr, ptr %t25 + %t73 = getelementptr inbounds %Str_Node, ptr %t72, i32 0, i32 1 + %t74 = load ptr, ptr %t73 + %t75 = load ptr, ptr %t1 + %t76 = load ptr, ptr %t25 + %t77 = getelementptr inbounds %Str_Node, ptr %t76, i32 0, i32 1 + %t78 = load ptr, ptr %t77 + %t79 = call ptr @fn_sconcat(ptr %t78, ptr @.str1037) + %t80 = call ptr @fn_sconcat(ptr @.str1036, ptr %t79) + %t81 = call ptr @fn_sconcat(ptr %t75, ptr %t80) + %t82 = call ptr @fn_sconcat(ptr @.str1035, ptr %t81) + %t83 = call ptr @fn_sconcat(ptr %t74, ptr %t82) + %t84 = call ptr @fn_sconcat(ptr @.str1034, ptr %t83) + call void @fn_emith(ptr %t84) + %t85 = load ptr, ptr %t25 + %t86 = getelementptr inbounds %Str_Node, ptr %t85, i32 0, i32 1 + %t87 = load ptr, ptr %t86 + %t88 = load ptr, ptr %t1 + %t89 = call ptr @fn_sconcat(ptr %t88, ptr @.str1040) + %t90 = call ptr @fn_sconcat(ptr @.str1039, ptr %t89) + %t91 = call ptr @fn_sconcat(ptr %t87, ptr %t90) + %t92 = call ptr @fn_sconcat(ptr @.str1038, ptr %t91) + call void @fn_emith(ptr %t92) + br label %ifend5 +ifend5: + %t93 = load i32, ptr %t11 + %t94 = add i32 %t93, 1 + store i32 %t94, ptr %t11 + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define void @fn_emit_ecs_allocator() { +entry: + %t1 = alloca ptr + %t2 = alloca i32 + %t24 = alloca ptr + %t0 = call ptr @fn_itoa(i32 1024) + store ptr %t0, ptr %t1 + call void @fn_emit(ptr @.str1041) + store i32 0, ptr %t2 + br label %wcond0 +wcond0: + %t3 = load i32, ptr %t2 + %t4 = load ptr, ptr @g_prog + %t5 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 1 + %t6 = load i32, ptr %t5 + %t7 = icmp slt i32 %t3, %t6 + %t8 = zext i1 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %wbody1, label %wend2 +wbody1: + %t10 = load ptr, ptr @g_prog + %t11 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 0 + %t12 = load ptr, ptr %t11 + %t13 = load i32, ptr %t2 + %t14 = getelementptr inbounds ptr, ptr %t12, i32 %t13 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 0 + %t17 = load i32, ptr %t16 + %t18 = icmp eq i32 %t17, 8 + %t19 = zext i1 %t18 to i32 + %t20 = icmp ne i32 %t19, 0 + br i1 %t20, label %then3, label %ifend5 +then3: + %t21 = load i32, ptr %t2 + %t22 = call ptr @fn_itoa(i32 %t21) + %t23 = call ptr @fn_sconcat(ptr @.str1042, ptr %t22) + store ptr %t23, ptr %t24 + call void @fn_emit(ptr @.str1043) + %t25 = load ptr, ptr %t24 + call void @fn_emit(ptr %t25) + call void @fn_emit(ptr @.str1044) + %t26 = load ptr, ptr %t1 + call void @fn_emit(ptr %t26) + call void @fn_emit(ptr @.str1045) + %t27 = load ptr, ptr @g_prog + %t28 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 0 + %t29 = load ptr, ptr %t28 + %t30 = load i32, ptr %t2 + %t31 = getelementptr inbounds ptr, ptr %t29, i32 %t30 + %t32 = load ptr, ptr %t31 + %t33 = getelementptr inbounds %Str_Node, ptr %t32, i32 0, i32 1 + %t34 = load ptr, ptr %t33 + call void @fn_emit(ptr %t34) + call void @fn_emit(ptr @.str1046) + call void @fn_emit(ptr @.str1047) + %t35 = load ptr, ptr %t24 + call void @fn_emit(ptr %t35) + call void @fn_emit(ptr @.str1048) + br label %ifend5 +ifend5: + %t36 = load i32, ptr %t2 + %t37 = add i32 %t36, 1 + store i32 %t37, ptr %t2 + br label %wcond0 +wend2: + call void @fn_emit(ptr @.str1049) + %t38 = load ptr, ptr %t1 + call void @fn_emit(ptr %t38) + call void @fn_emit(ptr @.str1050) + call void @fn_emit(ptr @.str1051) + call void @fn_emit(ptr @.str1052) + call void @fn_emit(ptr @.str1053) + call void @fn_emit(ptr @.str1054) + call void @fn_emit(ptr @.str1055) + call void @fn_emit(ptr @.str1056) + call void @fn_emit(ptr @.str1057) + call void @fn_emit(ptr @.str1058) + call void @fn_emit(ptr @.str1059) + %t39 = load ptr, ptr %t1 + call void @fn_emit(ptr %t39) + call void @fn_emit(ptr @.str1060) + call void @fn_emit(ptr @.str1061) + call void @fn_emit(ptr @.str1062) + call void @fn_emit(ptr @.str1063) + call void @fn_emit(ptr @.str1064) + call void @fn_emit(ptr @.str1065) + call void @fn_emit(ptr @.str1066) + call void @fn_emit(ptr @.str1067) + call void @fn_emit(ptr @.str1068) + call void @fn_emit(ptr @.str1069) + call void @fn_emit(ptr @.str1070) + call void @fn_emit(ptr @.str1071) + %t40 = load ptr, ptr %t1 + call void @fn_emit(ptr %t40) + call void @fn_emit(ptr @.str1072) + call void @fn_emit(ptr @.str1073) + call void @fn_emit(ptr @.str1074) + call void @fn_emit(ptr @.str1075) + call void @fn_emit(ptr @.str1076) + %t41 = load ptr, ptr %t1 + call void @fn_emit(ptr %t41) + call void @fn_emit(ptr @.str1077) + call void @fn_emit(ptr @.str1078) + call void @fn_emit(ptr @.str1079) + call void @fn_emit(ptr @.str1080) + call void @fn_emit(ptr @.str1081) + %t42 = load ptr, ptr %t1 + call void @fn_emit(ptr %t42) + call void @fn_emit(ptr @.str1082) + call void @fn_emit(ptr @.str1083) + call void @fn_emit(ptr @.str1084) + call void @fn_emit(ptr @.str1085) + call void @fn_emit(ptr @.str1086) + br label %ret +ret: + ret void +} + +define i32 @fn_find_arch_id(ptr %arg_name) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + store ptr %arg_name, ptr %t0 + store i32 0, ptr %t1 + store i32 1, ptr %t2 + br label %wcond0 +wcond0: + %t3 = load i32, ptr %t1 + %t4 = load ptr, ptr @g_prog + %t5 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 1 + %t6 = load i32, ptr %t5 + %t7 = icmp slt i32 %t3, %t6 + %t8 = zext i1 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %wbody1, label %wend2 +wbody1: + %t10 = load ptr, ptr @g_prog + %t11 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 0 + %t12 = load ptr, ptr %t11 + %t13 = load i32, ptr %t1 + %t14 = getelementptr inbounds ptr, ptr %t12, i32 %t13 + %t15 = load ptr, ptr %t14 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 0 + %t17 = load i32, ptr %t16 + %t18 = icmp eq i32 %t17, 10 + %t19 = zext i1 %t18 to i32 + %t20 = icmp ne i32 %t19, 0 + br i1 %t20, label %then3, label %ifend5 +then3: + %t21 = load ptr, ptr @g_prog + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 0 + %t23 = load ptr, ptr %t22 + %t24 = load i32, ptr %t1 + %t25 = getelementptr inbounds ptr, ptr %t23, i32 %t24 + %t26 = load ptr, ptr %t25 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 1 + %t28 = load ptr, ptr %t27 + %t29 = load ptr, ptr %t0 + %t30 = call i32 @fn_streq(ptr %t28, ptr %t29) + %t31 = icmp ne i32 %t30, 0 + br i1 %t31, label %then6, label %ifend8 +then6: + %t32 = load i32, ptr %t2 + store i32 %t32, ptr %retval + br label %ret +ifend8: + %t33 = load i32, ptr %t2 + %t34 = add i32 %t33, 1 + store i32 %t34, ptr %t2 + br label %ifend5 +ifend5: + %t35 = load i32, ptr %t1 + %t36 = add i32 %t35, 1 + store i32 %t36, ptr %t1 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t37 = load i32, ptr %retval + ret i32 %t37 +} + +define void @fn_emit_query(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t4 = alloca ptr + %t42 = alloca ptr + %t44 = alloca ptr + %t46 = alloca ptr + %t48 = alloca ptr + %t54 = alloca ptr + %t56 = alloca ptr + %t63 = alloca ptr + %t71 = alloca ptr + %t73 = alloca ptr + %t80 = alloca ptr + %t85 = alloca ptr + %t87 = alloca ptr + %t95 = alloca ptr + %t96 = alloca i32 + %t114 = alloca ptr + %t119 = alloca i32 + %t120 = alloca ptr + %t126 = alloca ptr + %t133 = alloca ptr + %t142 = alloca ptr + %t152 = alloca ptr + %t158 = alloca ptr + %t166 = alloca i32 + %t167 = alloca i32 + %t185 = alloca ptr + %t186 = alloca i32 + %t214 = alloca ptr + %t225 = alloca ptr + %t258 = alloca ptr + %t265 = alloca ptr + %t267 = alloca ptr + %t287 = alloca ptr + %t292 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = call ptr @fn_itoa(i32 1024) + store ptr %t1, ptr %t2 + %t3 = call ptr @fn_emit_alloca(ptr @.str1087) + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t4 + call void @fn_store_at(ptr @.str1088, ptr @.str1089, ptr %t5) + %t6 = load i32, ptr @g_nself + %t7 = load ptr, ptr @g_self_stk + %t8 = getelementptr inbounds %LSlice, ptr %t7, i32 0, i32 1 + %t9 = load i32, ptr %t8 + %t10 = icmp slt i32 %t6, %t9 + %t11 = zext i1 %t10 to i32 + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %else1 +then0: + %t13 = load ptr, ptr @g_self_stk + %t14 = getelementptr inbounds %LSlice, ptr %t13, i32 0, i32 0 + %t15 = load ptr, ptr %t14 + %t16 = load i32, ptr @g_nself + %t17 = getelementptr inbounds ptr, ptr %t15, i32 %t16 + %t18 = load ptr, ptr %t4 + store ptr %t18, ptr %t17 + br label %ifend2 +else1: + %t19 = load ptr, ptr @g_self_stk + %t20 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 1 + %t21 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 2 + %t22 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 0 + %t23 = load i32, ptr %t20 + %t24 = load i32, ptr %t21 + %t25 = icmp sge i32 %t23, %t24 + br i1 %t25, label %grow3, label %put4 +grow3: + %t26 = mul i32 %t24, 2 + %t27 = icmp eq i32 %t24, 0 + %t28 = select i1 %t27, i32 8, i32 %t26 + %t29 = getelementptr ptr, ptr null, i32 1 + %t30 = ptrtoint ptr %t29 to i64 + %t31 = zext i32 %t28 to i64 + %t32 = mul i64 %t31, %t30 + %t33 = load ptr, ptr %t22 + %t34 = call ptr @realloc(ptr %t33, i64 %t32) + store ptr %t34, ptr %t22 + store i32 %t28, ptr %t21 + br label %put4 +put4: + %t35 = load ptr, ptr %t4 + %t36 = load ptr, ptr %t22 + %t37 = getelementptr inbounds ptr, ptr %t36, i32 %t23 + store ptr %t35, ptr %t37 + %t38 = add i32 %t23, 1 + store i32 %t38, ptr %t20 + br label %ifend2 +ifend2: + %t39 = load i32, ptr @g_nself + %t40 = add i32 %t39, 1 + store i32 %t40, ptr @g_nself + %t41 = call ptr @fn_lbl(ptr @.str1090) + store ptr %t41, ptr %t42 + %t43 = call ptr @fn_lbl(ptr @.str1091) + store ptr %t43, ptr %t44 + %t45 = call ptr @fn_lbl(ptr @.str1092) + store ptr %t45, ptr %t46 + %t47 = call ptr @fn_lbl(ptr @.str1093) + store ptr %t47, ptr %t48 + call void @fn_emit(ptr @.str1094) + %t49 = load ptr, ptr %t42 + call void @fn_emit(ptr %t49) + call void @fn_emit(ptr @.str1095) + %t50 = load ptr, ptr %t42 + call void @fn_emit(ptr %t50) + call void @fn_emit(ptr @.str1096) + %t51 = load ptr, ptr %t4 + %t52 = call ptr @fn_sconcat(ptr @.str1097, ptr %t51) + %t53 = call ptr @fn_emit_bind(ptr %t52) + store ptr %t53, ptr %t54 + %t55 = call ptr @fn_emit_bind(ptr @.str1098) + store ptr %t55, ptr %t56 + %t57 = load ptr, ptr %t54 + %t58 = load ptr, ptr %t56 + %t59 = call ptr @fn_sconcat(ptr @.str1100, ptr %t58) + %t60 = call ptr @fn_sconcat(ptr %t57, ptr %t59) + %t61 = call ptr @fn_sconcat(ptr @.str1099, ptr %t60) + %t62 = call ptr @fn_emit_bind(ptr %t61) + store ptr %t62, ptr %t63 + call void @fn_emit(ptr @.str1101) + %t64 = load ptr, ptr %t63 + call void @fn_emit(ptr %t64) + call void @fn_emit(ptr @.str1102) + %t65 = load ptr, ptr %t44 + call void @fn_emit(ptr %t65) + call void @fn_emit(ptr @.str1103) + %t66 = load ptr, ptr %t48 + call void @fn_emit(ptr %t66) + call void @fn_emit(ptr @.str1104) + %t67 = load ptr, ptr %t44 + call void @fn_emit(ptr %t67) + call void @fn_emit(ptr @.str1105) + store i32 0, ptr @g_g_term + %t68 = load ptr, ptr %t4 + %t69 = call ptr @fn_sconcat(ptr @.str1106, ptr %t68) + %t70 = call ptr @fn_emit_bind(ptr %t69) + store ptr %t70, ptr %t71 + %t72 = call ptr @fn_nreg() + store ptr %t72, ptr %t73 + call void @fn_emit(ptr @.str1107) + %t74 = load ptr, ptr %t73 + call void @fn_emit(ptr %t74) + call void @fn_emit(ptr @.str1108) + %t75 = load ptr, ptr %t2 + call void @fn_emit(ptr %t75) + call void @fn_emit(ptr @.str1109) + %t76 = load ptr, ptr %t71 + call void @fn_emit(ptr %t76) + call void @fn_emit(ptr @.str1110) + %t77 = load ptr, ptr %t73 + %t78 = call ptr @fn_sconcat(ptr @.str1111, ptr %t77) + %t79 = call ptr @fn_emit_bind(ptr %t78) + store ptr %t79, ptr %t80 + %t81 = load ptr, ptr %t80 + %t82 = call ptr @fn_sconcat(ptr %t81, ptr @.str1113) + %t83 = call ptr @fn_sconcat(ptr @.str1112, ptr %t82) + %t84 = call ptr @fn_emit_bind(ptr %t83) + store ptr %t84, ptr %t85 + %t86 = call ptr @fn_lbl(ptr @.str1114) + store ptr %t86, ptr %t87 + call void @fn_emit(ptr @.str1115) + %t88 = load ptr, ptr %t85 + call void @fn_emit(ptr %t88) + call void @fn_emit(ptr @.str1116) + %t89 = load ptr, ptr %t87 + call void @fn_emit(ptr %t89) + call void @fn_emit(ptr @.str1117) + %t90 = load ptr, ptr %t46 + call void @fn_emit(ptr %t90) + call void @fn_emit(ptr @.str1118) + %t91 = load ptr, ptr %t87 + call void @fn_emit(ptr %t91) + call void @fn_emit(ptr @.str1119) + %t92 = load ptr, ptr %t0 + %t93 = getelementptr inbounds %Str_Node, ptr %t92, i32 0, i32 6 + %t94 = load ptr, ptr %t93 + store ptr %t94, ptr %t95 + store i32 0, ptr %t96 + br label %wcond5 +wcond5: + %t97 = load i32, ptr %t96 + %t98 = load ptr, ptr %t95 + %t99 = getelementptr inbounds %Str_Node, ptr %t98, i32 0, i32 7 + %t100 = load ptr, ptr %t99 + %t101 = getelementptr inbounds %LSlice, ptr %t100, i32 0, i32 1 + %t102 = load i32, ptr %t101 + %t103 = icmp slt i32 %t97, %t102 + %t104 = zext i1 %t103 to i32 + %t105 = icmp ne i32 %t104, 0 + br i1 %t105, label %wbody6, label %wend7 +wbody6: + %t106 = load ptr, ptr %t95 + %t107 = getelementptr inbounds %Str_Node, ptr %t106, i32 0, i32 7 + %t108 = load ptr, ptr %t107 + %t109 = getelementptr inbounds %LSlice, ptr %t108, i32 0, i32 0 + %t110 = load ptr, ptr %t109 + %t111 = load i32, ptr %t96 + %t112 = getelementptr inbounds ptr, ptr %t110, i32 %t111 + %t113 = load ptr, ptr %t112 + store ptr %t113, ptr %t114 + %t115 = load ptr, ptr %t114 + %t116 = getelementptr inbounds %Str_Node, ptr %t115, i32 0, i32 1 + %t117 = load ptr, ptr %t116 + %t118 = call i32 @fn_find_arch_id(ptr %t117) + store i32 %t118, ptr %t119 + store ptr @.str1120, ptr %t120 + %t121 = load i32, ptr %t119 + %t122 = icmp sgt i32 %t121, 0 + %t123 = zext i1 %t122 to i32 + %t124 = icmp ne i32 %t123, 0 + br i1 %t124, label %then8, label %else9 +then8: + %t125 = call ptr @fn_nreg() + store ptr %t125, ptr %t126 + call void @fn_emit(ptr @.str1121) + %t127 = load ptr, ptr %t126 + call void @fn_emit(ptr %t127) + call void @fn_emit(ptr @.str1122) + %t128 = load ptr, ptr %t2 + call void @fn_emit(ptr %t128) + call void @fn_emit(ptr @.str1123) + %t129 = load ptr, ptr %t71 + call void @fn_emit(ptr %t129) + call void @fn_emit(ptr @.str1124) + %t130 = load ptr, ptr %t126 + %t131 = call ptr @fn_sconcat(ptr @.str1125, ptr %t130) + %t132 = call ptr @fn_emit_bind(ptr %t131) + store ptr %t132, ptr %t133 + %t134 = load ptr, ptr %t133 + %t135 = load i32, ptr %t119 + %t136 = call ptr @fn_itoa(i32 %t135) + %t137 = call ptr @fn_sconcat(ptr @.str1127, ptr %t136) + %t138 = call ptr @fn_sconcat(ptr %t134, ptr %t137) + %t139 = call ptr @fn_sconcat(ptr @.str1126, ptr %t138) + %t140 = call ptr @fn_emit_bind(ptr %t139) + store ptr %t140, ptr %t120 + br label %ifend10 +else9: + %t141 = call ptr @fn_nreg() + store ptr %t141, ptr %t142 + call void @fn_emit(ptr @.str1128) + %t143 = load ptr, ptr %t142 + call void @fn_emit(ptr %t143) + call void @fn_emit(ptr @.str1129) + %t144 = load ptr, ptr %t2 + call void @fn_emit(ptr %t144) + call void @fn_emit(ptr @.str1130) + %t145 = load ptr, ptr %t114 + %t146 = getelementptr inbounds %Str_Node, ptr %t145, i32 0, i32 1 + %t147 = load ptr, ptr %t146 + call void @fn_emit(ptr %t147) + call void @fn_emit(ptr @.str1131) + %t148 = load ptr, ptr %t71 + call void @fn_emit(ptr %t148) + call void @fn_emit(ptr @.str1132) + %t149 = load ptr, ptr %t142 + %t150 = call ptr @fn_sconcat(ptr @.str1133, ptr %t149) + %t151 = call ptr @fn_emit_bind(ptr %t150) + store ptr %t151, ptr %t152 + %t153 = load ptr, ptr %t152 + %t154 = call ptr @fn_sconcat(ptr %t153, ptr @.str1135) + %t155 = call ptr @fn_sconcat(ptr @.str1134, ptr %t154) + %t156 = call ptr @fn_emit_bind(ptr %t155) + store ptr %t156, ptr %t120 + br label %ifend10 +ifend10: + %t157 = call ptr @fn_lbl(ptr @.str1136) + store ptr %t157, ptr %t158 + call void @fn_emit(ptr @.str1137) + %t159 = load ptr, ptr %t120 + call void @fn_emit(ptr %t159) + call void @fn_emit(ptr @.str1138) + %t160 = load ptr, ptr %t158 + call void @fn_emit(ptr %t160) + call void @fn_emit(ptr @.str1139) + %t161 = load ptr, ptr %t46 + call void @fn_emit(ptr %t161) + call void @fn_emit(ptr @.str1140) + %t162 = load ptr, ptr %t158 + call void @fn_emit(ptr %t162) + call void @fn_emit(ptr @.str1141) + %t163 = load i32, ptr %t96 + %t164 = add i32 %t163, 1 + store i32 %t164, ptr %t96 + br label %wcond5 +wend7: + %t165 = load i32, ptr @g_nloc + store i32 %t165, ptr %t166 + store i32 0, ptr %t167 + store i32 0, ptr %t96 + br label %wcond11 +wcond11: + %t168 = load i32, ptr %t96 + %t169 = load ptr, ptr %t95 + %t170 = getelementptr inbounds %Str_Node, ptr %t169, i32 0, i32 7 + %t171 = load ptr, ptr %t170 + %t172 = getelementptr inbounds %LSlice, ptr %t171, i32 0, i32 1 + %t173 = load i32, ptr %t172 + %t174 = icmp slt i32 %t168, %t173 + %t175 = zext i1 %t174 to i32 + %t176 = icmp ne i32 %t175, 0 + br i1 %t176, label %wbody12, label %wend13 +wbody12: + %t177 = load ptr, ptr %t95 + %t178 = getelementptr inbounds %Str_Node, ptr %t177, i32 0, i32 7 + %t179 = load ptr, ptr %t178 + %t180 = getelementptr inbounds %LSlice, ptr %t179, i32 0, i32 0 + %t181 = load ptr, ptr %t180 + %t182 = load i32, ptr %t96 + %t183 = getelementptr inbounds ptr, ptr %t181, i32 %t182 + %t184 = load ptr, ptr %t183 + store ptr %t184, ptr %t185 + %t187 = load ptr, ptr %t185 + %t188 = getelementptr inbounds %Str_Node, ptr %t187, i32 0, i32 2 + %t189 = load i32, ptr %t188 + %t190 = icmp eq i32 %t189, 0 + %t191 = zext i1 %t190 to i32 + %t192 = icmp ne i32 %t191, 0 + %t193 = zext i1 %t192 to i32 + store i32 %t193, ptr %t186 + br i1 %t192, label %sc14, label %scend15 +sc14: + %t194 = load ptr, ptr %t185 + %t195 = getelementptr inbounds %Str_Node, ptr %t194, i32 0, i32 1 + %t196 = load ptr, ptr %t195 + %t197 = call i32 @fn_find_arch_id(ptr %t196) + %t198 = icmp eq i32 %t197, 0 + %t199 = zext i1 %t198 to i32 + %t200 = icmp ne i32 %t199, 0 + %t201 = zext i1 %t200 to i32 + store i32 %t201, ptr %t186 + br label %scend15 +scend15: + %t202 = load i32, ptr %t186 + %t203 = icmp ne i32 %t202, 0 + br i1 %t203, label %then16, label %ifend18 +then16: + %t204 = load i32, ptr %t167 + %t205 = load ptr, ptr %t0 + %t206 = getelementptr inbounds %Str_Node, ptr %t205, i32 0, i32 7 + %t207 = load ptr, ptr %t206 + %t208 = getelementptr inbounds %LSlice, ptr %t207, i32 0, i32 1 + %t209 = load i32, ptr %t208 + %t210 = icmp slt i32 %t204, %t209 + %t211 = zext i1 %t210 to i32 + %t212 = icmp ne i32 %t211, 0 + br i1 %t212, label %then19, label %ifend21 +then19: + %t213 = call ptr @fn_nreg() + store ptr %t213, ptr %t214 + call void @fn_emit(ptr @.str1142) + %t215 = load ptr, ptr %t214 + call void @fn_emit(ptr %t215) + call void @fn_emit(ptr @.str1143) + %t216 = load ptr, ptr %t2 + call void @fn_emit(ptr %t216) + call void @fn_emit(ptr @.str1144) + %t217 = load ptr, ptr %t185 + %t218 = getelementptr inbounds %Str_Node, ptr %t217, i32 0, i32 1 + %t219 = load ptr, ptr %t218 + call void @fn_emit(ptr %t219) + call void @fn_emit(ptr @.str1145) + %t220 = load ptr, ptr %t185 + %t221 = getelementptr inbounds %Str_Node, ptr %t220, i32 0, i32 1 + %t222 = load ptr, ptr %t221 + call void @fn_emit(ptr %t222) + call void @fn_emit(ptr @.str1146) + %t223 = load ptr, ptr %t71 + call void @fn_emit(ptr %t223) + call void @fn_emit(ptr @.str1147) + %t224 = call ptr @fn_emit_alloca(ptr @.str1148) + store ptr %t224, ptr %t225 + call void @fn_emit(ptr @.str1149) + %t226 = load ptr, ptr %t214 + call void @fn_emit(ptr %t226) + call void @fn_emit(ptr @.str1150) + %t227 = load ptr, ptr %t225 + call void @fn_emit(ptr %t227) + call void @fn_emit(ptr @.str1151) + %t228 = load ptr, ptr %t0 + %t229 = getelementptr inbounds %Str_Node, ptr %t228, i32 0, i32 7 + %t230 = load ptr, ptr %t229 + %t231 = getelementptr inbounds %LSlice, ptr %t230, i32 0, i32 0 + %t232 = load ptr, ptr %t231 + %t233 = load i32, ptr %t167 + %t234 = getelementptr inbounds ptr, ptr %t232, i32 %t233 + %t235 = load ptr, ptr %t234 + %t236 = getelementptr inbounds %Str_Node, ptr %t235, i32 0, i32 1 + %t237 = load ptr, ptr %t236 + %t238 = load ptr, ptr %t225 + %t239 = load ptr, ptr %t185 + %t240 = getelementptr inbounds %Str_Node, ptr %t239, i32 0, i32 1 + %t241 = load ptr, ptr %t240 + call void @fn_loc_push(ptr %t237, ptr %t238, ptr %t241) + %t242 = load i32, ptr %t167 + %t243 = add i32 %t242, 1 + store i32 %t243, ptr %t167 + br label %ifend21 +ifend21: + br label %ifend18 +ifend18: + %t244 = load i32, ptr %t96 + %t245 = add i32 %t244, 1 + store i32 %t245, ptr %t96 + br label %wcond11 +wend13: + %t246 = load ptr, ptr %t0 + %t247 = getelementptr inbounds %Str_Node, ptr %t246, i32 0, i32 5 + %t248 = load ptr, ptr %t247 + %t249 = icmp eq ptr %t248, null + %t250 = zext i1 %t249 to i32 + %t251 = icmp eq i32 %t250, 0 + %t252 = zext i1 %t251 to i32 + %t253 = icmp ne i32 %t252, 0 + br i1 %t253, label %then22, label %ifend24 +then22: + %t254 = load ptr, ptr %t0 + %t255 = getelementptr inbounds %Str_Node, ptr %t254, i32 0, i32 5 + %t256 = load ptr, ptr %t255 + %t257 = call ptr @fn_emit_expr(ptr %t256) + store ptr %t257, ptr %t258 + %t259 = load ptr, ptr %t258 + %t260 = getelementptr inbounds %Str_Val, ptr %t259, i32 0, i32 0 + %t261 = load ptr, ptr %t260 + %t262 = call ptr @fn_sconcat(ptr %t261, ptr @.str1153) + %t263 = call ptr @fn_sconcat(ptr @.str1152, ptr %t262) + %t264 = call ptr @fn_emit_bind(ptr %t263) + store ptr %t264, ptr %t265 + %t266 = call ptr @fn_lbl(ptr @.str1154) + store ptr %t266, ptr %t267 + call void @fn_emit(ptr @.str1155) + %t268 = load ptr, ptr %t265 + call void @fn_emit(ptr %t268) + call void @fn_emit(ptr @.str1156) + %t269 = load ptr, ptr %t267 + call void @fn_emit(ptr %t269) + call void @fn_emit(ptr @.str1157) + %t270 = load ptr, ptr %t46 + call void @fn_emit(ptr %t270) + call void @fn_emit(ptr @.str1158) + %t271 = load ptr, ptr %t267 + call void @fn_emit(ptr %t271) + call void @fn_emit(ptr @.str1159) + br label %ifend24 +ifend24: + %t272 = load ptr, ptr %t46 + %t273 = load ptr, ptr %t48 + call void @fn_loop_push(ptr %t272, ptr %t273) + %t274 = load ptr, ptr %t0 + %t275 = getelementptr inbounds %Str_Node, ptr %t274, i32 0, i32 4 + %t276 = load ptr, ptr %t275 + call void @fn_emit_block(ptr %t276) + call void @fn_loop_pop() + %t277 = load i32, ptr %t166 + store i32 %t277, ptr @g_nloc + %t278 = load i32, ptr @g_g_term + %t279 = icmp eq i32 %t278, 0 + %t280 = zext i1 %t279 to i32 + %t281 = icmp ne i32 %t280, 0 + br i1 %t281, label %then25, label %ifend27 +then25: + call void @fn_emit(ptr @.str1160) + %t282 = load ptr, ptr %t46 + call void @fn_emit(ptr %t282) + call void @fn_emit(ptr @.str1161) + br label %ifend27 +ifend27: + %t283 = load ptr, ptr %t46 + call void @fn_emit(ptr %t283) + call void @fn_emit(ptr @.str1162) + %t284 = load ptr, ptr %t4 + %t285 = call ptr @fn_sconcat(ptr @.str1163, ptr %t284) + %t286 = call ptr @fn_emit_bind(ptr %t285) + store ptr %t286, ptr %t287 + %t288 = load ptr, ptr %t287 + %t289 = call ptr @fn_sconcat(ptr %t288, ptr @.str1165) + %t290 = call ptr @fn_sconcat(ptr @.str1164, ptr %t289) + %t291 = call ptr @fn_emit_bind(ptr %t290) + store ptr %t291, ptr %t292 + %t293 = load ptr, ptr %t292 + %t294 = load ptr, ptr %t4 + call void @fn_store_at(ptr @.str1166, ptr %t293, ptr %t294) + call void @fn_emit(ptr @.str1167) + %t295 = load ptr, ptr %t42 + call void @fn_emit(ptr %t295) + call void @fn_emit(ptr @.str1168) + %t296 = load ptr, ptr %t48 + call void @fn_emit(ptr %t296) + call void @fn_emit(ptr @.str1169) + store i32 0, ptr @g_g_term + %t297 = load i32, ptr @g_nself + %t298 = sub i32 %t297, 1 + store i32 %t298, ptr @g_nself + br label %ret +ret: + ret void +} + +define void @fn_emit_init_component(ptr %arg_e, ptr %arg_comp, ptr %arg_rec) { +entry: + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca ptr + %t4 = alloca ptr + %t7 = alloca ptr + %t15 = alloca ptr + %t22 = alloca ptr + %t28 = alloca i32 + %t46 = alloca ptr + %t48 = alloca ptr + %t58 = alloca ptr + %t59 = alloca ptr + %t75 = alloca ptr + %t90 = alloca i32 + %t108 = alloca ptr + %t114 = alloca i32 + %t120 = alloca ptr + %t130 = alloca ptr + store ptr %arg_e, ptr %t0 + store ptr %arg_comp, ptr %t1 + store ptr %arg_rec, ptr %t2 + %t3 = call ptr @fn_itoa(i32 1024) + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t1 + %t6 = call ptr @fn_find_comp(ptr %t5) + store ptr %t6, ptr %t7 + %t8 = load ptr, ptr %t7 + %t9 = icmp eq ptr %t8, null + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %then0, label %ifend2 +then0: + %t12 = load ptr, ptr %t1 + %t13 = call ptr @fn_sconcat(ptr @.str1170, ptr %t12) + call void @fn_perr(ptr %t13) + br label %ifend2 +ifend2: + %t14 = call ptr @fn_nreg() + store ptr %t14, ptr %t15 + call void @fn_emit(ptr @.str1171) + %t16 = load ptr, ptr %t15 + call void @fn_emit(ptr %t16) + call void @fn_emit(ptr @.str1172) + %t17 = load ptr, ptr %t4 + call void @fn_emit(ptr %t17) + call void @fn_emit(ptr @.str1173) + %t18 = load ptr, ptr %t1 + call void @fn_emit(ptr %t18) + call void @fn_emit(ptr @.str1174) + %t19 = load ptr, ptr %t0 + call void @fn_emit(ptr %t19) + call void @fn_emit(ptr @.str1175) + call void @fn_emit(ptr @.str1176) + %t20 = load ptr, ptr %t15 + call void @fn_emit(ptr %t20) + call void @fn_emit(ptr @.str1177) + %t21 = call ptr @fn_nreg() + store ptr %t21, ptr %t22 + call void @fn_emit(ptr @.str1178) + %t23 = load ptr, ptr %t22 + call void @fn_emit(ptr %t23) + call void @fn_emit(ptr @.str1179) + %t24 = load ptr, ptr %t4 + call void @fn_emit(ptr %t24) + call void @fn_emit(ptr @.str1180) + %t25 = load ptr, ptr %t1 + call void @fn_emit(ptr %t25) + call void @fn_emit(ptr @.str1181) + %t26 = load ptr, ptr %t1 + call void @fn_emit(ptr %t26) + call void @fn_emit(ptr @.str1182) + %t27 = load ptr, ptr %t0 + call void @fn_emit(ptr %t27) + call void @fn_emit(ptr @.str1183) + store i32 0, ptr %t28 + br label %wcond3 +wcond3: + %t29 = load i32, ptr %t28 + %t30 = load ptr, ptr %t7 + %t31 = getelementptr inbounds %Str_Node, ptr %t30, i32 0, i32 7 + %t32 = load ptr, ptr %t31 + %t33 = getelementptr inbounds %LSlice, ptr %t32, i32 0, i32 1 + %t34 = load i32, ptr %t33 + %t35 = icmp slt i32 %t29, %t34 + %t36 = zext i1 %t35 to i32 + %t37 = icmp ne i32 %t36, 0 + br i1 %t37, label %wbody4, label %wend5 +wbody4: + %t38 = load ptr, ptr %t7 + %t39 = getelementptr inbounds %Str_Node, ptr %t38, i32 0, i32 7 + %t40 = load ptr, ptr %t39 + %t41 = getelementptr inbounds %LSlice, ptr %t40, i32 0, i32 0 + %t42 = load ptr, ptr %t41 + %t43 = load i32, ptr %t28 + %t44 = getelementptr inbounds ptr, ptr %t42, i32 %t43 + %t45 = load ptr, ptr %t44 + store ptr %t45, ptr %t46 + %t47 = call ptr @fn_nreg() + store ptr %t47, ptr %t48 + call void @fn_emit(ptr @.str1184) + %t49 = load ptr, ptr %t48 + call void @fn_emit(ptr %t49) + call void @fn_emit(ptr @.str1185) + %t50 = load ptr, ptr %t1 + call void @fn_emit(ptr %t50) + call void @fn_emit(ptr @.str1186) + %t51 = load ptr, ptr %t22 + call void @fn_emit(ptr %t51) + call void @fn_emit(ptr @.str1187) + %t52 = load i32, ptr %t28 + %t53 = call ptr @fn_itoa(i32 %t52) + call void @fn_emit(ptr %t53) + call void @fn_emit(ptr @.str1188) + %t54 = load ptr, ptr %t46 + %t55 = getelementptr inbounds %Str_Node, ptr %t54, i32 0, i32 3 + %t56 = load ptr, ptr %t55 + %t57 = call ptr @fn_llty(ptr %t56) + store ptr %t57, ptr %t58 + store ptr @.str1189, ptr %t59 + %t60 = load ptr, ptr %t58 + %t61 = call i32 @fn_streq(ptr %t60, ptr @.str1190) + %t62 = icmp ne i32 %t61, 0 + br i1 %t62, label %then6, label %ifend8 +then6: + store ptr @.str1191, ptr %t59 + br label %ifend8 +ifend8: + %t63 = load ptr, ptr %t46 + %t64 = getelementptr inbounds %Str_Node, ptr %t63, i32 0, i32 4 + %t65 = load ptr, ptr %t64 + %t66 = icmp eq ptr %t65, null + %t67 = zext i1 %t66 to i32 + %t68 = icmp eq i32 %t67, 0 + %t69 = zext i1 %t68 to i32 + %t70 = icmp ne i32 %t69, 0 + br i1 %t70, label %then9, label %ifend11 +then9: + %t71 = load ptr, ptr %t46 + %t72 = getelementptr inbounds %Str_Node, ptr %t71, i32 0, i32 4 + %t73 = load ptr, ptr %t72 + %t74 = call ptr @fn_emit_expr(ptr %t73) + store ptr %t74, ptr %t75 + %t76 = load ptr, ptr %t75 + %t77 = getelementptr inbounds %Str_Val, ptr %t76, i32 0, i32 0 + %t78 = load ptr, ptr %t77 + store ptr %t78, ptr %t59 + br label %ifend11 +ifend11: + call void @fn_emit(ptr @.str1192) + %t79 = load ptr, ptr %t58 + call void @fn_emit(ptr %t79) + call void @fn_emit(ptr @.str1193) + %t80 = load ptr, ptr %t59 + call void @fn_emit(ptr %t80) + call void @fn_emit(ptr @.str1194) + %t81 = load ptr, ptr %t48 + call void @fn_emit(ptr %t81) + call void @fn_emit(ptr @.str1195) + %t82 = load i32, ptr %t28 + %t83 = add i32 %t82, 1 + store i32 %t83, ptr %t28 + br label %wcond3 +wend5: + %t84 = load ptr, ptr %t2 + %t85 = icmp eq ptr %t84, null + %t86 = zext i1 %t85 to i32 + %t87 = icmp eq i32 %t86, 0 + %t88 = zext i1 %t87 to i32 + %t89 = icmp ne i32 %t88, 0 + br i1 %t89, label %then12, label %ifend14 +then12: + store i32 0, ptr %t90 + br label %wcond15 +wcond15: + %t91 = load i32, ptr %t90 + %t92 = load ptr, ptr %t2 + %t93 = getelementptr inbounds %Str_Node, ptr %t92, i32 0, i32 7 + %t94 = load ptr, ptr %t93 + %t95 = getelementptr inbounds %LSlice, ptr %t94, i32 0, i32 1 + %t96 = load i32, ptr %t95 + %t97 = icmp slt i32 %t91, %t96 + %t98 = zext i1 %t97 to i32 + %t99 = icmp ne i32 %t98, 0 + br i1 %t99, label %wbody16, label %wend17 +wbody16: + %t100 = load ptr, ptr %t2 + %t101 = getelementptr inbounds %Str_Node, ptr %t100, i32 0, i32 7 + %t102 = load ptr, ptr %t101 + %t103 = getelementptr inbounds %LSlice, ptr %t102, i32 0, i32 0 + %t104 = load ptr, ptr %t103 + %t105 = load i32, ptr %t90 + %t106 = getelementptr inbounds ptr, ptr %t104, i32 %t105 + %t107 = load ptr, ptr %t106 + store ptr %t107, ptr %t108 + %t109 = load ptr, ptr %t7 + %t110 = load ptr, ptr %t108 + %t111 = getelementptr inbounds %Str_Node, ptr %t110, i32 0, i32 1 + %t112 = load ptr, ptr %t111 + %t113 = call i32 @fn_field_index(ptr %t109, ptr %t112) + store i32 %t113, ptr %t114 + %t115 = load i32, ptr %t114 + %t116 = icmp sge i32 %t115, 0 + %t117 = zext i1 %t116 to i32 + %t118 = icmp ne i32 %t117, 0 + br i1 %t118, label %then18, label %ifend20 +then18: + %t119 = call ptr @fn_nreg() + store ptr %t119, ptr %t120 + call void @fn_emit(ptr @.str1196) + %t121 = load ptr, ptr %t120 + call void @fn_emit(ptr %t121) + call void @fn_emit(ptr @.str1197) + %t122 = load ptr, ptr %t1 + call void @fn_emit(ptr %t122) + call void @fn_emit(ptr @.str1198) + %t123 = load ptr, ptr %t22 + call void @fn_emit(ptr %t123) + call void @fn_emit(ptr @.str1199) + %t124 = load i32, ptr %t114 + %t125 = call ptr @fn_itoa(i32 %t124) + call void @fn_emit(ptr %t125) + call void @fn_emit(ptr @.str1200) + %t126 = load ptr, ptr %t108 + %t127 = getelementptr inbounds %Str_Node, ptr %t126, i32 0, i32 4 + %t128 = load ptr, ptr %t127 + %t129 = call ptr @fn_emit_expr(ptr %t128) + store ptr %t129, ptr %t130 + call void @fn_emit(ptr @.str1201) + %t131 = load ptr, ptr %t7 + %t132 = load ptr, ptr %t108 + %t133 = getelementptr inbounds %Str_Node, ptr %t132, i32 0, i32 1 + %t134 = load ptr, ptr %t133 + %t135 = call ptr @fn_field_type(ptr %t131, ptr %t134) + %t136 = call ptr @fn_llty(ptr %t135) + call void @fn_emit(ptr %t136) + call void @fn_emit(ptr @.str1202) + %t137 = load ptr, ptr %t130 + %t138 = getelementptr inbounds %Str_Val, ptr %t137, i32 0, i32 0 + %t139 = load ptr, ptr %t138 + call void @fn_emit(ptr %t139) + call void @fn_emit(ptr @.str1203) + %t140 = load ptr, ptr %t120 + call void @fn_emit(ptr %t140) + call void @fn_emit(ptr @.str1204) + br label %ifend20 +ifend20: + %t141 = load i32, ptr %t90 + %t142 = add i32 %t141, 1 + store i32 %t142, ptr %t90 + br label %wcond15 +wend17: + br label %ifend14 +ifend14: + br label %ret +ret: + ret void +} + +define void @fn_emit_spawn(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t7 = alloca i32 + %t13 = alloca ptr + %t15 = alloca ptr + %t26 = alloca ptr + %t27 = alloca i32 + %t47 = alloca ptr + %t48 = alloca ptr + %t49 = alloca i32 + %t89 = alloca i32 + store ptr %arg_st, ptr %t0 + %t1 = call ptr @fn_emit_bind(ptr @.str1205) + store ptr %t1, ptr %t2 + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 1 + %t5 = load ptr, ptr %t4 + %t6 = call i32 @fn_find_arch_id(ptr %t5) + store i32 %t6, ptr %t7 + %t8 = load i32, ptr %t7 + %t9 = icmp sgt i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %then0, label %else1 +then0: + %t12 = call ptr @fn_itoa(i32 1024) + store ptr %t12, ptr %t13 + %t14 = call ptr @fn_nreg() + store ptr %t14, ptr %t15 + call void @fn_emit(ptr @.str1206) + %t16 = load ptr, ptr %t15 + call void @fn_emit(ptr %t16) + call void @fn_emit(ptr @.str1207) + %t17 = load ptr, ptr %t13 + call void @fn_emit(ptr %t17) + call void @fn_emit(ptr @.str1208) + %t18 = load ptr, ptr %t2 + call void @fn_emit(ptr %t18) + call void @fn_emit(ptr @.str1209) + call void @fn_emit(ptr @.str1210) + %t19 = load i32, ptr %t7 + %t20 = call ptr @fn_itoa(i32 %t19) + call void @fn_emit(ptr %t20) + call void @fn_emit(ptr @.str1211) + %t21 = load ptr, ptr %t15 + call void @fn_emit(ptr %t21) + call void @fn_emit(ptr @.str1212) + %t22 = load ptr, ptr %t0 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 1 + %t24 = load ptr, ptr %t23 + %t25 = call ptr @fn_find_arch(ptr %t24) + store ptr %t25, ptr %t26 + store i32 0, ptr %t27 + br label %wcond3 +wcond3: + %t28 = load i32, ptr %t27 + %t29 = load ptr, ptr %t26 + %t30 = getelementptr inbounds %Str_Node, ptr %t29, i32 0, i32 7 + %t31 = load ptr, ptr %t30 + %t32 = getelementptr inbounds %LSlice, ptr %t31, i32 0, i32 1 + %t33 = load i32, ptr %t32 + %t34 = icmp slt i32 %t28, %t33 + %t35 = zext i1 %t34 to i32 + %t36 = icmp ne i32 %t35, 0 + br i1 %t36, label %wbody4, label %wend5 +wbody4: + %t37 = load ptr, ptr %t26 + %t38 = getelementptr inbounds %Str_Node, ptr %t37, i32 0, i32 7 + %t39 = load ptr, ptr %t38 + %t40 = getelementptr inbounds %LSlice, ptr %t39, i32 0, i32 0 + %t41 = load ptr, ptr %t40 + %t42 = load i32, ptr %t27 + %t43 = getelementptr inbounds ptr, ptr %t41, i32 %t42 + %t44 = load ptr, ptr %t43 + %t45 = getelementptr inbounds %Str_Node, ptr %t44, i32 0, i32 1 + %t46 = load ptr, ptr %t45 + store ptr %t46, ptr %t47 + store ptr null, ptr %t48 + store i32 0, ptr %t49 + br label %wcond6 +wcond6: + %t50 = load i32, ptr %t49 + %t51 = load ptr, ptr %t0 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 7 + %t53 = load ptr, ptr %t52 + %t54 = getelementptr inbounds %LSlice, ptr %t53, i32 0, i32 1 + %t55 = load i32, ptr %t54 + %t56 = icmp slt i32 %t50, %t55 + %t57 = zext i1 %t56 to i32 + %t58 = icmp ne i32 %t57, 0 + br i1 %t58, label %wbody7, label %wend8 +wbody7: + %t59 = load ptr, ptr %t0 + %t60 = getelementptr inbounds %Str_Node, ptr %t59, i32 0, i32 7 + %t61 = load ptr, ptr %t60 + %t62 = getelementptr inbounds %LSlice, ptr %t61, i32 0, i32 0 + %t63 = load ptr, ptr %t62 + %t64 = load i32, ptr %t49 + %t65 = getelementptr inbounds ptr, ptr %t63, i32 %t64 + %t66 = load ptr, ptr %t65 + %t67 = getelementptr inbounds %Str_Node, ptr %t66, i32 0, i32 1 + %t68 = load ptr, ptr %t67 + %t69 = load ptr, ptr %t47 + %t70 = call i32 @fn_streq(ptr %t68, ptr %t69) + %t71 = icmp ne i32 %t70, 0 + br i1 %t71, label %then9, label %ifend11 +then9: + %t72 = load ptr, ptr %t0 + %t73 = getelementptr inbounds %Str_Node, ptr %t72, i32 0, i32 7 + %t74 = load ptr, ptr %t73 + %t75 = getelementptr inbounds %LSlice, ptr %t74, i32 0, i32 0 + %t76 = load ptr, ptr %t75 + %t77 = load i32, ptr %t49 + %t78 = getelementptr inbounds ptr, ptr %t76, i32 %t77 + %t79 = load ptr, ptr %t78 + %t80 = getelementptr inbounds %Str_Node, ptr %t79, i32 0, i32 4 + %t81 = load ptr, ptr %t80 + store ptr %t81, ptr %t48 + br label %ifend11 +ifend11: + %t82 = load i32, ptr %t49 + %t83 = add i32 %t82, 1 + store i32 %t83, ptr %t49 + br label %wcond6 +wend8: + %t84 = load ptr, ptr %t2 + %t85 = load ptr, ptr %t47 + %t86 = load ptr, ptr %t48 + call void @fn_emit_init_component(ptr %t84, ptr %t85, ptr %t86) + %t87 = load i32, ptr %t27 + %t88 = add i32 %t87, 1 + store i32 %t88, ptr %t27 + br label %wcond3 +wend5: + br label %ifend2 +else1: + store i32 0, ptr %t89 + br label %wcond12 +wcond12: + %t90 = load i32, ptr %t89 + %t91 = load ptr, ptr %t0 + %t92 = getelementptr inbounds %Str_Node, ptr %t91, i32 0, i32 7 + %t93 = load ptr, ptr %t92 + %t94 = getelementptr inbounds %LSlice, ptr %t93, i32 0, i32 1 + %t95 = load i32, ptr %t94 + %t96 = icmp slt i32 %t90, %t95 + %t97 = zext i1 %t96 to i32 + %t98 = icmp ne i32 %t97, 0 + br i1 %t98, label %wbody13, label %wend14 +wbody13: + %t99 = load ptr, ptr %t2 + %t100 = load ptr, ptr %t0 + %t101 = getelementptr inbounds %Str_Node, ptr %t100, i32 0, i32 7 + %t102 = load ptr, ptr %t101 + %t103 = getelementptr inbounds %LSlice, ptr %t102, i32 0, i32 0 + %t104 = load ptr, ptr %t103 + %t105 = load i32, ptr %t89 + %t106 = getelementptr inbounds ptr, ptr %t104, i32 %t105 + %t107 = load ptr, ptr %t106 + %t108 = getelementptr inbounds %Str_Node, ptr %t107, i32 0, i32 1 + %t109 = load ptr, ptr %t108 + %t110 = load ptr, ptr %t0 + %t111 = getelementptr inbounds %Str_Node, ptr %t110, i32 0, i32 7 + %t112 = load ptr, ptr %t111 + %t113 = getelementptr inbounds %LSlice, ptr %t112, i32 0, i32 0 + %t114 = load ptr, ptr %t113 + %t115 = load i32, ptr %t89 + %t116 = getelementptr inbounds ptr, ptr %t114, i32 %t115 + %t117 = load ptr, ptr %t116 + %t118 = getelementptr inbounds %Str_Node, ptr %t117, i32 0, i32 4 + %t119 = load ptr, ptr %t118 + call void @fn_emit_init_component(ptr %t99, ptr %t109, ptr %t119) + %t120 = load i32, ptr %t89 + %t121 = add i32 %t120, 1 + store i32 %t121, ptr %t89 + br label %wcond12 +wend14: + br label %ifend2 +ifend2: + br label %ret +ret: + ret void +} + +define void @fn_emit_despawn(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t5 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_emit_expr(ptr %t3) + store ptr %t4, ptr %t5 + call void @fn_emit(ptr @.str1213) + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Val, ptr %t6, i32 0, i32 0 + %t8 = load ptr, ptr %t7 + call void @fn_emit(ptr %t8) + call void @fn_emit(ptr @.str1214) + br label %ret +ret: + ret void +} + +define void @fn_emit_system_fn(ptr %arg_sys) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t5 = alloca ptr + store ptr %arg_sys, ptr %t0 + store i32 0, ptr @g_ll_t + store i32 0, ptr @g_ll_lbl + store i32 0, ptr @g_g_term + call void @fn_loc_reset() + store i32 0, ptr @g_nloop + store i32 0, ptr @g_nself + store ptr @.str1215, ptr @g_ret_ty + %t1 = call ptr @fn_buf_new() + store ptr %t1, ptr %t2 + %t3 = call ptr @fn_buf_new() + store ptr %t3, ptr @g_falloc + %t4 = load ptr, ptr @g_code + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t2 + store ptr %t6, ptr @g_code + %t7 = load ptr, ptr %t0 + %t8 = getelementptr inbounds %Str_Node, ptr %t7, i32 0, i32 4 + %t9 = load ptr, ptr %t8 + call void @fn_emit_block(ptr %t9) + %t10 = load i32, ptr @g_g_term + %t11 = icmp eq i32 %t10, 0 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then0, label %ifend2 +then0: + call void @fn_emit(ptr @.str1216) + br label %ifend2 +ifend2: + call void @fn_emit(ptr @.str1217) + %t14 = load ptr, ptr %t5 + store ptr %t14, ptr @g_code + call void @fn_emit(ptr @.str1218) + %t15 = load ptr, ptr %t0 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 1 + %t17 = load ptr, ptr %t16 + call void @fn_emit(ptr %t17) + call void @fn_emit(ptr @.str1219) + %t18 = load ptr, ptr @g_falloc + %t19 = call ptr @fn_buf_str(ptr %t18) + call void @fn_emit(ptr %t19) + %t20 = load ptr, ptr %t2 + %t21 = call ptr @fn_buf_str(ptr %t20) + call void @fn_emit(ptr %t21) + call void @fn_emit(ptr @.str1220) + br label %ret +ret: + ret void +} + +define void @fn_emit_calls_for_phase(ptr %arg_phase) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + %t15 = alloca ptr + %t16 = alloca i32 + store ptr %arg_phase, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr @g_prog + %t4 = getelementptr inbounds %LSlice, ptr %t3, i32 0, i32 1 + %t5 = load i32, ptr %t4 + %t6 = icmp slt i32 %t2, %t5 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t1 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + store ptr %t14, ptr %t15 + %t17 = load ptr, ptr %t15 + %t18 = getelementptr inbounds %Str_Node, ptr %t17, i32 0, i32 0 + %t19 = load i32, ptr %t18 + %t20 = icmp eq i32 %t19, 9 + %t21 = zext i1 %t20 to i32 + %t22 = icmp ne i32 %t21, 0 + %t23 = zext i1 %t22 to i32 + store i32 %t23, ptr %t16 + br i1 %t22, label %sc3, label %scend4 +sc3: + %t24 = load ptr, ptr %t15 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 3 + %t26 = load ptr, ptr %t25 + %t27 = load ptr, ptr %t0 + %t28 = call i32 @fn_streq(ptr %t26, ptr %t27) + %t29 = icmp ne i32 %t28, 0 + %t30 = zext i1 %t29 to i32 + store i32 %t30, ptr %t16 + br label %scend4 +scend4: + %t31 = load i32, ptr %t16 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then5, label %ifend7 +then5: + call void @fn_emit(ptr @.str1221) + %t33 = load ptr, ptr %t15 + %t34 = getelementptr inbounds %Str_Node, ptr %t33, i32 0, i32 1 + %t35 = load ptr, ptr %t34 + call void @fn_emit(ptr %t35) + call void @fn_emit(ptr @.str1222) + br label %ifend7 +ifend7: + %t36 = load i32, ptr %t1 + %t37 = add i32 %t36, 1 + store i32 %t37, ptr %t1 + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define void @fn_emit_game_main() { +entry: + %t0 = alloca i32 + %t34 = alloca ptr + %t39 = alloca ptr + %t47 = alloca ptr + %t52 = alloca ptr + %t59 = alloca ptr + %t69 = alloca ptr + store i32 0, ptr %t0 + br label %wcond0 +wcond0: + %t1 = load i32, ptr %t0 + %t2 = load ptr, ptr @g_prog + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + %t4 = load i32, ptr %t3 + %t5 = icmp slt i32 %t1, %t4 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + %t8 = load ptr, ptr @g_prog + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + %t10 = load ptr, ptr %t9 + %t11 = load i32, ptr %t0 + %t12 = getelementptr inbounds ptr, ptr %t10, i32 %t11 + %t13 = load ptr, ptr %t12 + %t14 = getelementptr inbounds %Str_Node, ptr %t13, i32 0, i32 0 + %t15 = load i32, ptr %t14 + %t16 = icmp eq i32 %t15, 9 + %t17 = zext i1 %t16 to i32 + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %then3, label %ifend5 +then3: + %t19 = load ptr, ptr @g_prog + %t20 = getelementptr inbounds %LSlice, ptr %t19, i32 0, i32 0 + %t21 = load ptr, ptr %t20 + %t22 = load i32, ptr %t0 + %t23 = getelementptr inbounds ptr, ptr %t21, i32 %t22 + %t24 = load ptr, ptr %t23 + call void @fn_emit_system_fn(ptr %t24) + br label %ifend5 +ifend5: + %t25 = load i32, ptr %t0 + %t26 = add i32 %t25, 1 + store i32 %t26, ptr %t0 + br label %wcond0 +wend2: + call void @fn_emit(ptr @.str1223) + call void @fn_emit(ptr @.str1224) + call void @fn_emit(ptr @.str1225) + %t27 = call ptr @fn_find_fn(ptr @.str1226) + %t28 = icmp eq ptr %t27, null + %t29 = zext i1 %t28 to i32 + %t30 = icmp eq i32 %t29, 0 + %t31 = zext i1 %t30 to i32 + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then6, label %ifend8 +then6: + call void @fn_emit(ptr @.str1227) + br label %ifend8 +ifend8: + call void @fn_emit_calls_for_phase(ptr @.str1228) + call void @fn_emit(ptr @.str1229) + call void @fn_emit(ptr @.str1230) + %t33 = call ptr @fn_emit_bind(ptr @.str1231) + store ptr %t33, ptr %t34 + %t35 = load ptr, ptr %t34 + %t36 = call ptr @fn_sconcat(ptr %t35, ptr @.str1233) + %t37 = call ptr @fn_sconcat(ptr @.str1232, ptr %t36) + %t38 = call ptr @fn_emit_bind(ptr %t37) + store ptr %t38, ptr %t39 + %t40 = call ptr @fn_find_fn(ptr @.str1234) + %t41 = icmp eq ptr %t40, null + %t42 = zext i1 %t41 to i32 + %t43 = icmp eq i32 %t42, 0 + %t44 = zext i1 %t43 to i32 + %t45 = icmp ne i32 %t44, 0 + br i1 %t45, label %then9, label %else10 +then9: + %t46 = call ptr @fn_emit_bind(ptr @.str1235) + store ptr %t46, ptr %t47 + %t48 = load ptr, ptr %t47 + %t49 = call ptr @fn_sconcat(ptr %t48, ptr @.str1237) + %t50 = call ptr @fn_sconcat(ptr @.str1236, ptr %t49) + %t51 = call ptr @fn_emit_bind(ptr %t50) + store ptr %t51, ptr %t52 + %t53 = load ptr, ptr %t39 + %t54 = load ptr, ptr %t52 + %t55 = call ptr @fn_sconcat(ptr @.str1239, ptr %t54) + %t56 = call ptr @fn_sconcat(ptr %t53, ptr %t55) + %t57 = call ptr @fn_sconcat(ptr @.str1238, ptr %t56) + %t58 = call ptr @fn_emit_bind(ptr %t57) + store ptr %t58, ptr %t59 + call void @fn_emit(ptr @.str1240) + %t60 = load ptr, ptr %t59 + call void @fn_emit(ptr %t60) + call void @fn_emit(ptr @.str1241) + br label %ifend11 +else10: + call void @fn_emit(ptr @.str1242) + %t61 = load ptr, ptr %t39 + call void @fn_emit(ptr %t61) + call void @fn_emit(ptr @.str1243) + br label %ifend11 +ifend11: + call void @fn_emit(ptr @.str1244) + %t62 = call ptr @fn_find_fn(ptr @.str1245) + %t63 = icmp eq ptr %t62, null + %t64 = zext i1 %t63 to i32 + %t65 = icmp eq i32 %t64, 0 + %t66 = zext i1 %t65 to i32 + %t67 = icmp ne i32 %t66, 0 + br i1 %t67, label %then12, label %ifend14 +then12: + %t68 = call ptr @fn_emit_bind(ptr @.str1246) + store ptr %t68, ptr %t69 + call void @fn_emit(ptr @.str1247) + %t70 = load ptr, ptr %t69 + call void @fn_emit(ptr %t70) + call void @fn_emit(ptr @.str1248) + br label %ifend14 +ifend14: + call void @fn_emit_calls_for_phase(ptr @.str1249) + call void @fn_emit_calls_for_phase(ptr @.str1250) + call void @fn_emit_calls_for_phase(ptr @.str1251) + call void @fn_emit_calls_for_phase(ptr @.str1252) + call void @fn_emit_calls_for_phase(ptr @.str1253) + call void @fn_emit(ptr @.str1254) + call void @fn_emit(ptr @.str1255) + %t71 = call ptr @fn_find_fn(ptr @.str1256) + %t72 = icmp eq ptr %t71, null + %t73 = zext i1 %t72 to i32 + %t74 = icmp eq i32 %t73, 0 + %t75 = zext i1 %t74 to i32 + %t76 = icmp ne i32 %t75, 0 + br i1 %t76, label %then15, label %ifend17 +then15: + call void @fn_emit(ptr @.str1257) + br label %ifend17 +ifend17: + call void @fn_emit(ptr @.str1258) + br label %ret +ret: + ret void +} + +define void @fn_emit_machine(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t5 = alloca ptr + %t12 = alloca ptr + %t49 = alloca ptr + %t50 = alloca i32 + %t68 = alloca ptr + %t73 = alloca ptr + %t82 = alloca ptr + %t84 = alloca ptr + %t86 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 4 + %t3 = load ptr, ptr %t2 + %t4 = call ptr @fn_emit_expr(ptr %t3) + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Val, ptr %t6, i32 0, i32 0 + %t8 = load ptr, ptr %t7 + %t9 = call ptr @fn_sconcat(ptr %t8, ptr @.str1260) + %t10 = call ptr @fn_sconcat(ptr @.str1259, ptr %t9) + %t11 = call ptr @fn_emit_bind(ptr %t10) + store ptr %t11, ptr %t12 + %t13 = load i32, ptr @g_nmach + %t14 = load ptr, ptr @g_mach_stk + %t15 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 1 + %t16 = load i32, ptr %t15 + %t17 = icmp slt i32 %t13, %t16 + %t18 = zext i1 %t17 to i32 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then0, label %else1 +then0: + %t20 = load ptr, ptr @g_mach_stk + %t21 = getelementptr inbounds %LSlice, ptr %t20, i32 0, i32 0 + %t22 = load ptr, ptr %t21 + %t23 = load i32, ptr @g_nmach + %t24 = getelementptr inbounds ptr, ptr %t22, i32 %t23 + %t25 = load ptr, ptr %t0 + store ptr %t25, ptr %t24 + br label %ifend2 +else1: + %t26 = load ptr, ptr @g_mach_stk + %t27 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 1 + %t28 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 2 + %t29 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 0 + %t30 = load i32, ptr %t27 + %t31 = load i32, ptr %t28 + %t32 = icmp sge i32 %t30, %t31 + br i1 %t32, label %grow3, label %put4 +grow3: + %t33 = mul i32 %t31, 2 + %t34 = icmp eq i32 %t31, 0 + %t35 = select i1 %t34, i32 8, i32 %t33 + %t36 = getelementptr ptr, ptr null, i32 1 + %t37 = ptrtoint ptr %t36 to i64 + %t38 = zext i32 %t35 to i64 + %t39 = mul i64 %t38, %t37 + %t40 = load ptr, ptr %t29 + %t41 = call ptr @realloc(ptr %t40, i64 %t39) + store ptr %t41, ptr %t29 + store i32 %t35, ptr %t28 + br label %put4 +put4: + %t42 = load ptr, ptr %t0 + %t43 = load ptr, ptr %t29 + %t44 = getelementptr inbounds ptr, ptr %t43, i32 %t30 + store ptr %t42, ptr %t44 + %t45 = add i32 %t30, 1 + store i32 %t45, ptr %t27 + br label %ifend2 +ifend2: + %t46 = load i32, ptr @g_nmach + %t47 = add i32 %t46, 1 + store i32 %t47, ptr @g_nmach + %t48 = call ptr @fn_lbl(ptr @.str1261) + store ptr %t48, ptr %t49 + store i32 0, ptr %t50 + br label %wcond5 +wcond5: + %t51 = load i32, ptr %t50 + %t52 = load ptr, ptr %t0 + %t53 = getelementptr inbounds %Str_Node, ptr %t52, i32 0, i32 7 + %t54 = load ptr, ptr %t53 + %t55 = getelementptr inbounds %LSlice, ptr %t54, i32 0, i32 1 + %t56 = load i32, ptr %t55 + %t57 = icmp slt i32 %t51, %t56 + %t58 = zext i1 %t57 to i32 + %t59 = icmp ne i32 %t58, 0 + br i1 %t59, label %wbody6, label %wend7 +wbody6: + %t60 = load ptr, ptr %t0 + %t61 = getelementptr inbounds %Str_Node, ptr %t60, i32 0, i32 7 + %t62 = load ptr, ptr %t61 + %t63 = getelementptr inbounds %LSlice, ptr %t62, i32 0, i32 0 + %t64 = load ptr, ptr %t63 + %t65 = load i32, ptr %t50 + %t66 = getelementptr inbounds ptr, ptr %t64, i32 %t65 + %t67 = load ptr, ptr %t66 + store ptr %t67, ptr %t68 + %t69 = load ptr, ptr %t68 + %t70 = getelementptr inbounds %Str_Node, ptr %t69, i32 0, i32 5 + %t71 = load ptr, ptr %t70 + %t72 = call ptr @fn_emit_expr(ptr %t71) + store ptr %t72, ptr %t73 + %t74 = load ptr, ptr %t12 + %t75 = load ptr, ptr %t73 + %t76 = getelementptr inbounds %Str_Val, ptr %t75, i32 0, i32 0 + %t77 = load ptr, ptr %t76 + %t78 = call ptr @fn_sconcat(ptr @.str1263, ptr %t77) + %t79 = call ptr @fn_sconcat(ptr %t74, ptr %t78) + %t80 = call ptr @fn_sconcat(ptr @.str1262, ptr %t79) + %t81 = call ptr @fn_emit_bind(ptr %t80) + store ptr %t81, ptr %t82 + %t83 = call ptr @fn_lbl(ptr @.str1264) + store ptr %t83, ptr %t84 + %t85 = call ptr @fn_lbl(ptr @.str1265) + store ptr %t85, ptr %t86 + call void @fn_emit(ptr @.str1266) + %t87 = load ptr, ptr %t82 + call void @fn_emit(ptr %t87) + call void @fn_emit(ptr @.str1267) + %t88 = load ptr, ptr %t84 + call void @fn_emit(ptr %t88) + call void @fn_emit(ptr @.str1268) + %t89 = load ptr, ptr %t86 + call void @fn_emit(ptr %t89) + call void @fn_emit(ptr @.str1269) + %t90 = load ptr, ptr %t84 + call void @fn_emit(ptr %t90) + call void @fn_emit(ptr @.str1270) + store i32 0, ptr @g_g_term + %t91 = load ptr, ptr %t68 + %t92 = getelementptr inbounds %Str_Node, ptr %t91, i32 0, i32 4 + %t93 = load ptr, ptr %t92 + call void @fn_emit_block(ptr %t93) + %t94 = load i32, ptr @g_g_term + %t95 = icmp eq i32 %t94, 0 + %t96 = zext i1 %t95 to i32 + %t97 = icmp ne i32 %t96, 0 + br i1 %t97, label %then8, label %ifend10 +then8: + call void @fn_emit(ptr @.str1271) + %t98 = load ptr, ptr %t49 + call void @fn_emit(ptr %t98) + call void @fn_emit(ptr @.str1272) + br label %ifend10 +ifend10: + %t99 = load ptr, ptr %t86 + call void @fn_emit(ptr %t99) + call void @fn_emit(ptr @.str1273) + store i32 0, ptr @g_g_term + %t100 = load i32, ptr %t50 + %t101 = add i32 %t100, 1 + store i32 %t101, ptr %t50 + br label %wcond5 +wend7: + %t102 = load i32, ptr @g_g_term + %t103 = icmp eq i32 %t102, 0 + %t104 = zext i1 %t103 to i32 + %t105 = icmp ne i32 %t104, 0 + br i1 %t105, label %then11, label %ifend13 +then11: + call void @fn_emit(ptr @.str1274) + %t106 = load ptr, ptr %t49 + call void @fn_emit(ptr %t106) + call void @fn_emit(ptr @.str1275) + br label %ifend13 +ifend13: + %t107 = load ptr, ptr %t49 + call void @fn_emit(ptr %t107) + call void @fn_emit(ptr @.str1276) + store i32 0, ptr @g_g_term + %t108 = load i32, ptr @g_nmach + %t109 = sub i32 %t108, 1 + store i32 %t109, ptr @g_nmach + br label %ret +ret: + ret void +} + +define void @fn_emit_become(ptr %arg_st) { +entry: + %t0 = alloca ptr + %t12 = alloca ptr + %t13 = alloca ptr + %t14 = alloca i32 + %t61 = alloca ptr + %t66 = alloca ptr + store ptr %arg_st, ptr %t0 + %t1 = load i32, ptr @g_nmach + %t2 = icmp eq i32 %t1, 0 + %t3 = zext i1 %t2 to i32 + %t4 = icmp ne i32 %t3, 0 + br i1 %t4, label %then0, label %ifend2 +then0: + call void @fn_perr(ptr @.str1277) + br label %ifend2 +ifend2: + %t5 = load ptr, ptr @g_mach_stk + %t6 = getelementptr inbounds %LSlice, ptr %t5, i32 0, i32 0 + %t7 = load ptr, ptr %t6 + %t8 = load i32, ptr @g_nmach + %t9 = sub i32 %t8, 1 + %t10 = getelementptr inbounds ptr, ptr %t7, i32 %t9 + %t11 = load ptr, ptr %t10 + store ptr %t11, ptr %t12 + store ptr null, ptr %t13 + store i32 0, ptr %t14 + br label %wcond3 +wcond3: + %t15 = load i32, ptr %t14 + %t16 = load ptr, ptr %t12 + %t17 = getelementptr inbounds %Str_Node, ptr %t16, i32 0, i32 7 + %t18 = load ptr, ptr %t17 + %t19 = getelementptr inbounds %LSlice, ptr %t18, i32 0, i32 1 + %t20 = load i32, ptr %t19 + %t21 = icmp slt i32 %t15, %t20 + %t22 = zext i1 %t21 to i32 + %t23 = icmp ne i32 %t22, 0 + br i1 %t23, label %wbody4, label %wend5 +wbody4: + %t24 = load ptr, ptr %t12 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 7 + %t26 = load ptr, ptr %t25 + %t27 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 0 + %t28 = load ptr, ptr %t27 + %t29 = load i32, ptr %t14 + %t30 = getelementptr inbounds ptr, ptr %t28, i32 %t29 + %t31 = load ptr, ptr %t30 + %t32 = getelementptr inbounds %Str_Node, ptr %t31, i32 0, i32 1 + %t33 = load ptr, ptr %t32 + %t34 = load ptr, ptr %t0 + %t35 = getelementptr inbounds %Str_Node, ptr %t34, i32 0, i32 1 + %t36 = load ptr, ptr %t35 + %t37 = call i32 @fn_streq(ptr %t33, ptr %t36) + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %then6, label %ifend8 +then6: + %t39 = load ptr, ptr %t12 + %t40 = getelementptr inbounds %Str_Node, ptr %t39, i32 0, i32 7 + %t41 = load ptr, ptr %t40 + %t42 = getelementptr inbounds %LSlice, ptr %t41, i32 0, i32 0 + %t43 = load ptr, ptr %t42 + %t44 = load i32, ptr %t14 + %t45 = getelementptr inbounds ptr, ptr %t43, i32 %t44 + %t46 = load ptr, ptr %t45 + store ptr %t46, ptr %t13 + br label %ifend8 +ifend8: + %t47 = load i32, ptr %t14 + %t48 = add i32 %t47, 1 + store i32 %t48, ptr %t14 + br label %wcond3 +wend5: + %t49 = load ptr, ptr %t13 + %t50 = icmp eq ptr %t49, null + %t51 = zext i1 %t50 to i32 + %t52 = icmp ne i32 %t51, 0 + br i1 %t52, label %then9, label %ifend11 +then9: + %t53 = load ptr, ptr %t0 + %t54 = getelementptr inbounds %Str_Node, ptr %t53, i32 0, i32 1 + %t55 = load ptr, ptr %t54 + %t56 = call ptr @fn_sconcat(ptr @.str1278, ptr %t55) + call void @fn_perr(ptr %t56) + br label %ifend11 +ifend11: + %t57 = load ptr, ptr %t12 + %t58 = getelementptr inbounds %Str_Node, ptr %t57, i32 0, i32 4 + %t59 = load ptr, ptr %t58 + %t60 = call ptr @fn_emit_expr(ptr %t59) + store ptr %t60, ptr %t61 + %t62 = load ptr, ptr %t13 + %t63 = getelementptr inbounds %Str_Node, ptr %t62, i32 0, i32 5 + %t64 = load ptr, ptr %t63 + %t65 = call ptr @fn_emit_expr(ptr %t64) + store ptr %t65, ptr %t66 + call void @fn_emit(ptr @.str1279) + %t67 = load ptr, ptr %t61 + %t68 = getelementptr inbounds %Str_Val, ptr %t67, i32 0, i32 0 + %t69 = load ptr, ptr %t68 + call void @fn_emit(ptr %t69) + call void @fn_emit(ptr @.str1280) + %t70 = load ptr, ptr %t66 + %t71 = getelementptr inbounds %Str_Val, ptr %t70, i32 0, i32 0 + %t72 = load ptr, ptr %t71 + call void @fn_emit(ptr %t72) + call void @fn_emit(ptr @.str1281) + br label %ret +ret: + ret void +} + +define void @fn_emit_io(ptr %arg_fn2, ptr %arg_p, ptr %arg_bytes) { +entry: + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca ptr + %t6 = alloca ptr + store ptr %arg_fn2, ptr %t0 + store ptr %arg_p, ptr %t1 + store ptr %arg_bytes, ptr %t2 + %t3 = load i32, ptr @g_g_iok + %t4 = call ptr @fn_itoa(i32 %t3) + %t5 = call ptr @fn_sconcat(ptr @.str1282, ptr %t4) + store ptr %t5, ptr %t6 + %t7 = load i32, ptr @g_g_iok + %t8 = add i32 %t7, 1 + store i32 %t8, ptr @g_g_iok + call void @fn_emit(ptr @.str1283) + %t9 = load ptr, ptr %t6 + call void @fn_emit(ptr %t9) + call void @fn_emit(ptr @.str1284) + %t10 = load ptr, ptr %t0 + call void @fn_emit(ptr %t10) + call void @fn_emit(ptr @.str1285) + %t11 = load ptr, ptr %t1 + call void @fn_emit(ptr %t11) + call void @fn_emit(ptr @.str1286) + %t12 = load ptr, ptr %t2 + call void @fn_emit(ptr %t12) + call void @fn_emit(ptr @.str1287) + br label %ret +ret: + ret void +} + +define void @fn_emit_snapshot_blocks(ptr %arg_fn2) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t9 = alloca i32 + %t40 = alloca i32 + %t67 = alloca ptr + %t71 = alloca ptr + store ptr %arg_fn2, ptr %t0 + store i32 0, ptr @g_g_iok + %t1 = call ptr @fn_itoa(i32 1024) + store ptr %t1, ptr %t2 + %t3 = load ptr, ptr %t0 + call void @fn_emit_io(ptr %t3, ptr @.str1288, ptr @.str1289) + %t4 = load ptr, ptr %t0 + call void @fn_emit_io(ptr %t4, ptr @.str1290, ptr @.str1291) + call void @fn_emit(ptr @.str1292) + %t5 = load ptr, ptr %t2 + call void @fn_emit(ptr %t5) + call void @fn_emit(ptr @.str1293) + %t6 = load ptr, ptr %t0 + call void @fn_emit_io(ptr %t6, ptr @.str1294, ptr @.str1295) + %t7 = load ptr, ptr %t0 + call void @fn_emit_io(ptr %t7, ptr @.str1296, ptr @.str1297) + %t8 = load ptr, ptr %t0 + call void @fn_emit_io(ptr %t8, ptr @.str1298, ptr @.str1299) + store i32 0, ptr %t9 + br label %wcond0 +wcond0: + %t10 = load i32, ptr %t9 + %t11 = load ptr, ptr @g_prog + %t12 = getelementptr inbounds %LSlice, ptr %t11, i32 0, i32 1 + %t13 = load i32, ptr %t12 + %t14 = icmp slt i32 %t10, %t13 + %t15 = zext i1 %t14 to i32 + %t16 = icmp ne i32 %t15, 0 + br i1 %t16, label %wbody1, label %wend2 +wbody1: + %t17 = load ptr, ptr @g_prog + %t18 = getelementptr inbounds %LSlice, ptr %t17, i32 0, i32 0 + %t19 = load ptr, ptr %t18 + %t20 = load i32, ptr %t9 + %t21 = getelementptr inbounds ptr, ptr %t19, i32 %t20 + %t22 = load ptr, ptr %t21 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 0 + %t24 = load i32, ptr %t23 + %t25 = icmp eq i32 %t24, 2 + %t26 = zext i1 %t25 to i32 + %t27 = icmp ne i32 %t26, 0 + br i1 %t27, label %then3, label %ifend5 +then3: + %t28 = load ptr, ptr %t0 + %t29 = load ptr, ptr @g_prog + %t30 = getelementptr inbounds %LSlice, ptr %t29, i32 0, i32 0 + %t31 = load ptr, ptr %t30 + %t32 = load i32, ptr %t9 + %t33 = getelementptr inbounds ptr, ptr %t31, i32 %t32 + %t34 = load ptr, ptr %t33 + %t35 = getelementptr inbounds %Str_Node, ptr %t34, i32 0, i32 1 + %t36 = load ptr, ptr %t35 + %t37 = call ptr @fn_sconcat(ptr @.str1300, ptr %t36) + call void @fn_emit_io(ptr %t28, ptr %t37, ptr @.str1301) + br label %ifend5 +ifend5: + %t38 = load i32, ptr %t9 + %t39 = add i32 %t38, 1 + store i32 %t39, ptr %t9 + br label %wcond0 +wend2: + store i32 0, ptr %t40 + store i32 0, ptr %t9 + br label %wcond6 +wcond6: + %t41 = load i32, ptr %t9 + %t42 = load ptr, ptr @g_prog + %t43 = getelementptr inbounds %LSlice, ptr %t42, i32 0, i32 1 + %t44 = load i32, ptr %t43 + %t45 = icmp slt i32 %t41, %t44 + %t46 = zext i1 %t45 to i32 + %t47 = icmp ne i32 %t46, 0 + br i1 %t47, label %wbody7, label %wend8 +wbody7: + %t48 = load ptr, ptr @g_prog + %t49 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 0 + %t50 = load ptr, ptr %t49 + %t51 = load i32, ptr %t9 + %t52 = getelementptr inbounds ptr, ptr %t50, i32 %t51 + %t53 = load ptr, ptr %t52 + %t54 = getelementptr inbounds %Str_Node, ptr %t53, i32 0, i32 0 + %t55 = load i32, ptr %t54 + %t56 = icmp eq i32 %t55, 8 + %t57 = zext i1 %t56 to i32 + %t58 = icmp ne i32 %t57, 0 + br i1 %t58, label %then9, label %ifend11 +then9: + %t59 = load ptr, ptr @g_prog + %t60 = getelementptr inbounds %LSlice, ptr %t59, i32 0, i32 0 + %t61 = load ptr, ptr %t60 + %t62 = load i32, ptr %t9 + %t63 = getelementptr inbounds ptr, ptr %t61, i32 %t62 + %t64 = load ptr, ptr %t63 + %t65 = getelementptr inbounds %Str_Node, ptr %t64, i32 0, i32 1 + %t66 = load ptr, ptr %t65 + store ptr %t66, ptr %t67 + %t68 = load i32, ptr %t40 + %t69 = call ptr @fn_itoa(i32 %t68) + %t70 = call ptr @fn_sconcat(ptr @.str1302, ptr %t69) + store ptr %t70, ptr %t71 + call void @fn_emit(ptr @.str1303) + %t72 = load ptr, ptr %t71 + call void @fn_emit(ptr %t72) + call void @fn_emit(ptr @.str1304) + %t73 = load ptr, ptr %t67 + call void @fn_emit(ptr %t73) + call void @fn_emit(ptr @.str1305) + %t74 = load ptr, ptr %t2 + call void @fn_emit(ptr %t74) + call void @fn_emit(ptr @.str1306) + %t75 = load ptr, ptr %t0 + %t76 = load ptr, ptr %t67 + %t77 = call ptr @fn_sconcat(ptr @.str1307, ptr %t76) + %t78 = load ptr, ptr %t71 + call void @fn_emit_io(ptr %t75, ptr %t77, ptr %t78) + %t79 = load ptr, ptr %t0 + %t80 = load ptr, ptr %t67 + %t81 = call ptr @fn_sconcat(ptr @.str1308, ptr %t80) + %t82 = load ptr, ptr %t2 + call void @fn_emit_io(ptr %t79, ptr %t81, ptr %t82) + %t83 = load i32, ptr %t40 + %t84 = add i32 %t83, 1 + store i32 %t84, ptr %t40 + br label %ifend11 +ifend11: + %t85 = load i32, ptr %t9 + %t86 = add i32 %t85, 1 + store i32 %t86, ptr %t9 + br label %wcond6 +wend8: + br label %ret +ret: + ret void +} + +define void @fn_emit_snapshot() { +entry: + %t5 = alloca i32 + %t11 = alloca i32 + call void @fn_emith(ptr @.str1309) + call void @fn_emith(ptr @.str1310) + call void @fn_emith(ptr @.str1311) + %t0 = call ptr @fn_find_fn(ptr @.str1312) + %t1 = icmp eq ptr %t0, null + %t2 = zext i1 %t1 to i32 + %t3 = icmp eq i32 %t2, 0 + %t4 = zext i1 %t3 to i32 + store i32 %t4, ptr %t5 + %t6 = call ptr @fn_find_fn(ptr @.str1313) + %t7 = icmp eq ptr %t6, null + %t8 = zext i1 %t7 to i32 + %t9 = icmp eq i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + store i32 %t10, ptr %t11 + call void @fn_emit(ptr @.str1314) + call void @fn_emit(ptr @.str1315) + call void @fn_emit(ptr @.str1316) + call void @fn_emit(ptr @.str1317) + call void @fn_emit_snapshot_blocks(ptr @.str1318) + %t12 = load i32, ptr %t5 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then0, label %ifend2 +then0: + call void @fn_emit(ptr @.str1319) + br label %ifend2 +ifend2: + call void @fn_emit(ptr @.str1320) + call void @fn_emit(ptr @.str1321) + call void @fn_emit(ptr @.str1322) + call void @fn_emit(ptr @.str1323) + call void @fn_emit(ptr @.str1324) + call void @fn_emit_snapshot_blocks(ptr @.str1325) + %t14 = load i32, ptr %t11 + %t15 = icmp ne i32 %t14, 0 + br i1 %t15, label %then3, label %ifend5 +then3: + call void @fn_emit(ptr @.str1326) + br label %ifend5 +ifend5: + call void @fn_emit(ptr @.str1327) + br label %ret +ret: + ret void +} + +define i32 @fn_ui_wtype(ptr %arg_w) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t4 = alloca ptr + store ptr %arg_w, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 1 + %t3 = load ptr, ptr %t2 + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t4 + %t6 = call i32 @fn_streq(ptr %t5, ptr @.str1328) + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + store i32 0, ptr %retval + br label %ret +ifend2: + %t8 = load ptr, ptr %t4 + %t9 = call i32 @fn_streq(ptr %t8, ptr @.str1329) + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %then3, label %ifend5 +then3: + store i32 1, ptr %retval + br label %ret +ifend5: + %t11 = load ptr, ptr %t4 + %t12 = call i32 @fn_streq(ptr %t11, ptr @.str1330) + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then6, label %ifend8 +then6: + store i32 2, ptr %retval + br label %ret +ifend8: + %t14 = load ptr, ptr %t4 + %t15 = call i32 @fn_streq(ptr %t14, ptr @.str1331) + %t16 = icmp ne i32 %t15, 0 + br i1 %t16, label %then9, label %ifend11 +then9: + store i32 3, ptr %retval + br label %ret +ifend11: + %t17 = load ptr, ptr %t4 + %t18 = call i32 @fn_streq(ptr %t17, ptr @.str1332) + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then12, label %ifend14 +then12: + store i32 4, ptr %retval + br label %ret +ifend14: + %t20 = load ptr, ptr %t4 + %t21 = call i32 @fn_streq(ptr %t20, ptr @.str1333) + %t22 = icmp ne i32 %t21, 0 + br i1 %t22, label %then15, label %ifend17 +then15: + store i32 5, ptr %retval + br label %ret +ifend17: + %t23 = load ptr, ptr %t4 + %t24 = call i32 @fn_streq(ptr %t23, ptr @.str1334) + %t25 = icmp ne i32 %t24, 0 + br i1 %t25, label %then18, label %ifend20 +then18: + store i32 6, ptr %retval + br label %ret +ifend20: + store i32 0, ptr %retval + br label %ret +ret: + %t26 = load i32, ptr %retval + ret i32 %t26 +} + +define ptr @fn_ui_prop(ptr %arg_w, ptr %arg_key) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + store ptr %arg_w, ptr %t0 + store ptr %arg_key, ptr %t1 + store i32 0, ptr %t2 + br label %wcond0 +wcond0: + %t3 = load i32, ptr %t2 + %t4 = load ptr, ptr %t0 + %t5 = getelementptr inbounds %Str_Node, ptr %t4, i32 0, i32 5 + %t6 = load ptr, ptr %t5 + %t7 = getelementptr inbounds %Str_Node, ptr %t6, i32 0, i32 7 + %t8 = load ptr, ptr %t7 + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 1 + %t10 = load i32, ptr %t9 + %t11 = icmp slt i32 %t3, %t10 + %t12 = zext i1 %t11 to i32 + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %wbody1, label %wend2 +wbody1: + %t14 = load ptr, ptr %t0 + %t15 = getelementptr inbounds %Str_Node, ptr %t14, i32 0, i32 5 + %t16 = load ptr, ptr %t15 + %t17 = getelementptr inbounds %Str_Node, ptr %t16, i32 0, i32 7 + %t18 = load ptr, ptr %t17 + %t19 = getelementptr inbounds %LSlice, ptr %t18, i32 0, i32 0 + %t20 = load ptr, ptr %t19 + %t21 = load i32, ptr %t2 + %t22 = getelementptr inbounds ptr, ptr %t20, i32 %t21 + %t23 = load ptr, ptr %t22 + %t24 = getelementptr inbounds %Str_Node, ptr %t23, i32 0, i32 1 + %t25 = load ptr, ptr %t24 + %t26 = load ptr, ptr %t1 + %t27 = call i32 @fn_streq(ptr %t25, ptr %t26) + %t28 = icmp ne i32 %t27, 0 + br i1 %t28, label %then3, label %ifend5 +then3: + %t29 = load ptr, ptr %t0 + %t30 = getelementptr inbounds %Str_Node, ptr %t29, i32 0, i32 5 + %t31 = load ptr, ptr %t30 + %t32 = getelementptr inbounds %Str_Node, ptr %t31, i32 0, i32 7 + %t33 = load ptr, ptr %t32 + %t34 = getelementptr inbounds %LSlice, ptr %t33, i32 0, i32 0 + %t35 = load ptr, ptr %t34 + %t36 = load i32, ptr %t2 + %t37 = getelementptr inbounds ptr, ptr %t35, i32 %t36 + %t38 = load ptr, ptr %t37 + %t39 = getelementptr inbounds %Str_Node, ptr %t38, i32 0, i32 4 + %t40 = load ptr, ptr %t39 + store ptr %t40, ptr %retval + br label %ret +ifend5: + %t41 = load i32, ptr %t2 + %t42 = add i32 %t41, 1 + store i32 %t42, ptr %t2 + br label %wcond0 +wend2: + store ptr null, ptr %retval + br label %ret +ret: + %t43 = load ptr, ptr %retval + ret ptr %t43 +} + +define void @fn_ui_flatten(ptr %arg_w, i32 %arg_parent) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + %t5 = alloca i32 + %t46 = alloca i32 + store ptr %arg_w, ptr %t0 + store i32 %arg_parent, ptr %t1 + %t2 = load ptr, ptr @g_uiw + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + %t4 = load i32, ptr %t3 + store i32 %t4, ptr %t5 + %t6 = load ptr, ptr @g_uiw + %t7 = getelementptr inbounds %LSlice, ptr %t6, i32 0, i32 1 + %t8 = getelementptr inbounds %LSlice, ptr %t6, i32 0, i32 2 + %t9 = getelementptr inbounds %LSlice, ptr %t6, i32 0, i32 0 + %t10 = load i32, ptr %t7 + %t11 = load i32, ptr %t8 + %t12 = icmp sge i32 %t10, %t11 + br i1 %t12, label %grow0, label %put1 +grow0: + %t13 = mul i32 %t11, 2 + %t14 = icmp eq i32 %t11, 0 + %t15 = select i1 %t14, i32 8, i32 %t13 + %t16 = getelementptr ptr, ptr null, i32 1 + %t17 = ptrtoint ptr %t16 to i64 + %t18 = zext i32 %t15 to i64 + %t19 = mul i64 %t18, %t17 + %t20 = load ptr, ptr %t9 + %t21 = call ptr @realloc(ptr %t20, i64 %t19) + store ptr %t21, ptr %t9 + store i32 %t15, ptr %t8 + br label %put1 +put1: + %t22 = load ptr, ptr %t0 + %t23 = load ptr, ptr %t9 + %t24 = getelementptr inbounds ptr, ptr %t23, i32 %t10 + store ptr %t22, ptr %t24 + %t25 = add i32 %t10, 1 + store i32 %t25, ptr %t7 + %t26 = load ptr, ptr @g_uiw_parent + %t27 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 1 + %t28 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 2 + %t29 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 0 + %t30 = load i32, ptr %t27 + %t31 = load i32, ptr %t28 + %t32 = icmp sge i32 %t30, %t31 + br i1 %t32, label %grow2, label %put3 +grow2: + %t33 = mul i32 %t31, 2 + %t34 = icmp eq i32 %t31, 0 + %t35 = select i1 %t34, i32 8, i32 %t33 + %t36 = getelementptr i32, ptr null, i32 1 + %t37 = ptrtoint ptr %t36 to i64 + %t38 = zext i32 %t35 to i64 + %t39 = mul i64 %t38, %t37 + %t40 = load ptr, ptr %t29 + %t41 = call ptr @realloc(ptr %t40, i64 %t39) + store ptr %t41, ptr %t29 + store i32 %t35, ptr %t28 + br label %put3 +put3: + %t42 = load i32, ptr %t1 + %t43 = load ptr, ptr %t29 + %t44 = getelementptr inbounds i32, ptr %t43, i32 %t30 + store i32 %t42, ptr %t44 + %t45 = add i32 %t30, 1 + store i32 %t45, ptr %t27 + store i32 0, ptr %t46 + br label %wcond4 +wcond4: + %t47 = load i32, ptr %t46 + %t48 = load ptr, ptr %t0 + %t49 = getelementptr inbounds %Str_Node, ptr %t48, i32 0, i32 7 + %t50 = load ptr, ptr %t49 + %t51 = getelementptr inbounds %LSlice, ptr %t50, i32 0, i32 1 + %t52 = load i32, ptr %t51 + %t53 = icmp slt i32 %t47, %t52 + %t54 = zext i1 %t53 to i32 + %t55 = icmp ne i32 %t54, 0 + br i1 %t55, label %wbody5, label %wend6 +wbody5: + %t56 = load ptr, ptr %t0 + %t57 = getelementptr inbounds %Str_Node, ptr %t56, i32 0, i32 7 + %t58 = load ptr, ptr %t57 + %t59 = getelementptr inbounds %LSlice, ptr %t58, i32 0, i32 0 + %t60 = load ptr, ptr %t59 + %t61 = load i32, ptr %t46 + %t62 = getelementptr inbounds ptr, ptr %t60, i32 %t61 + %t63 = load ptr, ptr %t62 + %t64 = load i32, ptr %t5 + call void @fn_ui_flatten(ptr %t63, i32 %t64) + %t65 = load i32, ptr %t46 + %t66 = add i32 %t65, 1 + store i32 %t66, ptr %t46 + br label %wcond4 +wend6: + br label %ret +ret: + ret void +} + +define void @fn_ui_flatten_all() { +entry: + %t18 = alloca i32 + %t26 = alloca i32 + %t0 = getelementptr %LSlice, ptr null, i32 1 + %t1 = ptrtoint ptr %t0 to i64 + %t2 = call ptr @malloc(i64 %t1) + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 0 + store ptr null, ptr %t3 + %t4 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + store i32 0, ptr %t4 + %t5 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 2 + store i32 0, ptr %t5 + store ptr %t2, ptr @g_uiw + %t6 = getelementptr %LSlice, ptr null, i32 1 + %t7 = ptrtoint ptr %t6 to i64 + %t8 = call ptr @malloc(i64 %t7) + %t9 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 0 + store ptr null, ptr %t9 + %t10 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 1 + store i32 0, ptr %t10 + %t11 = getelementptr inbounds %LSlice, ptr %t8, i32 0, i32 2 + store i32 0, ptr %t11 + store ptr %t8, ptr @g_uiw_parent + %t12 = getelementptr %LSlice, ptr null, i32 1 + %t13 = ptrtoint ptr %t12 to i64 + %t14 = call ptr @malloc(i64 %t13) + %t15 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 0 + store ptr null, ptr %t15 + %t16 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 1 + store i32 0, ptr %t16 + %t17 = getelementptr inbounds %LSlice, ptr %t14, i32 0, i32 2 + store i32 0, ptr %t17 + store ptr %t14, ptr @g_ui_roots + store i32 0, ptr %t18 + br label %wcond0 +wcond0: + %t19 = load i32, ptr %t18 + %t20 = load ptr, ptr @g_prog + %t21 = getelementptr inbounds %LSlice, ptr %t20, i32 0, i32 1 + %t22 = load i32, ptr %t21 + %t23 = icmp slt i32 %t19, %t22 + %t24 = zext i1 %t23 to i32 + %t25 = icmp ne i32 %t24, 0 + br i1 %t25, label %wbody1, label %wend2 +wbody1: + %t27 = load ptr, ptr @g_prog + %t28 = getelementptr inbounds %LSlice, ptr %t27, i32 0, i32 0 + %t29 = load ptr, ptr %t28 + %t30 = load i32, ptr %t18 + %t31 = getelementptr inbounds ptr, ptr %t29, i32 %t30 + %t32 = load ptr, ptr %t31 + %t33 = getelementptr inbounds %Str_Node, ptr %t32, i32 0, i32 0 + %t34 = load i32, ptr %t33 + %t35 = icmp eq i32 %t34, 12 + %t36 = zext i1 %t35 to i32 + %t37 = icmp ne i32 %t36, 0 + %t38 = zext i1 %t37 to i32 + store i32 %t38, ptr %t26 + br i1 %t37, label %sc3, label %scend4 +sc3: + %t39 = load ptr, ptr @g_prog + %t40 = getelementptr inbounds %LSlice, ptr %t39, i32 0, i32 0 + %t41 = load ptr, ptr %t40 + %t42 = load i32, ptr %t18 + %t43 = getelementptr inbounds ptr, ptr %t41, i32 %t42 + %t44 = load ptr, ptr %t43 + %t45 = getelementptr inbounds %Str_Node, ptr %t44, i32 0, i32 2 + %t46 = load i32, ptr %t45 + %t47 = icmp eq i32 %t46, 1 + %t48 = zext i1 %t47 to i32 + %t49 = icmp ne i32 %t48, 0 + %t50 = zext i1 %t49 to i32 + store i32 %t50, ptr %t26 + br label %scend4 +scend4: + %t51 = load i32, ptr %t26 + %t52 = icmp ne i32 %t51, 0 + br i1 %t52, label %then5, label %ifend7 +then5: + %t53 = load ptr, ptr @g_ui_roots + %t54 = getelementptr inbounds %LSlice, ptr %t53, i32 0, i32 1 + %t55 = getelementptr inbounds %LSlice, ptr %t53, i32 0, i32 2 + %t56 = getelementptr inbounds %LSlice, ptr %t53, i32 0, i32 0 + %t57 = load i32, ptr %t54 + %t58 = load i32, ptr %t55 + %t59 = icmp sge i32 %t57, %t58 + br i1 %t59, label %grow8, label %put9 +grow8: + %t60 = mul i32 %t58, 2 + %t61 = icmp eq i32 %t58, 0 + %t62 = select i1 %t61, i32 8, i32 %t60 + %t63 = getelementptr i32, ptr null, i32 1 + %t64 = ptrtoint ptr %t63 to i64 + %t65 = zext i32 %t62 to i64 + %t66 = mul i64 %t65, %t64 + %t67 = load ptr, ptr %t56 + %t68 = call ptr @realloc(ptr %t67, i64 %t66) + store ptr %t68, ptr %t56 + store i32 %t62, ptr %t55 + br label %put9 +put9: + %t69 = load ptr, ptr @g_uiw + %t70 = getelementptr inbounds %LSlice, ptr %t69, i32 0, i32 1 + %t71 = load i32, ptr %t70 + %t72 = load ptr, ptr %t56 + %t73 = getelementptr inbounds i32, ptr %t72, i32 %t57 + store i32 %t71, ptr %t73 + %t74 = add i32 %t57, 1 + store i32 %t74, ptr %t54 + %t75 = load ptr, ptr @g_prog + %t76 = getelementptr inbounds %LSlice, ptr %t75, i32 0, i32 0 + %t77 = load ptr, ptr %t76 + %t78 = load i32, ptr %t18 + %t79 = getelementptr inbounds ptr, ptr %t77, i32 %t78 + %t80 = load ptr, ptr %t79 + %t81 = getelementptr inbounds %Str_Node, ptr %t80, i32 0, i32 4 + %t82 = load ptr, ptr %t81 + %t83 = sub i32 0, 1 + call void @fn_ui_flatten(ptr %t82, i32 %t83) + br label %ifend7 +ifend7: + %t84 = load i32, ptr %t18 + %t85 = add i32 %t84, 1 + store i32 %t85, ptr %t18 + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define i32 @fn_has_ui() { +entry: + %retval = alloca i32 + %t0 = alloca i32 + %t8 = alloca i32 + store i32 0, ptr %t0 + br label %wcond0 +wcond0: + %t1 = load i32, ptr %t0 + %t2 = load ptr, ptr @g_prog + %t3 = getelementptr inbounds %LSlice, ptr %t2, i32 0, i32 1 + %t4 = load i32, ptr %t3 + %t5 = icmp slt i32 %t1, %t4 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %wbody1, label %wend2 +wbody1: + %t9 = load ptr, ptr @g_prog + %t10 = getelementptr inbounds %LSlice, ptr %t9, i32 0, i32 0 + %t11 = load ptr, ptr %t10 + %t12 = load i32, ptr %t0 + %t13 = getelementptr inbounds ptr, ptr %t11, i32 %t12 + %t14 = load ptr, ptr %t13 + %t15 = getelementptr inbounds %Str_Node, ptr %t14, i32 0, i32 0 + %t16 = load i32, ptr %t15 + %t17 = icmp eq i32 %t16, 12 + %t18 = zext i1 %t17 to i32 + %t19 = icmp ne i32 %t18, 0 + %t20 = zext i1 %t19 to i32 + store i32 %t20, ptr %t8 + br i1 %t19, label %sc3, label %scend4 +sc3: + %t21 = load ptr, ptr @g_prog + %t22 = getelementptr inbounds %LSlice, ptr %t21, i32 0, i32 0 + %t23 = load ptr, ptr %t22 + %t24 = load i32, ptr %t0 + %t25 = getelementptr inbounds ptr, ptr %t23, i32 %t24 + %t26 = load ptr, ptr %t25 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 2 + %t28 = load i32, ptr %t27 + %t29 = icmp eq i32 %t28, 1 + %t30 = zext i1 %t29 to i32 + %t31 = icmp ne i32 %t30, 0 + %t32 = zext i1 %t31 to i32 + store i32 %t32, ptr %t8 + br label %scend4 +scend4: + %t33 = load i32, ptr %t8 + %t34 = icmp ne i32 %t33, 0 + br i1 %t34, label %then5, label %ifend7 +then5: + store i32 1, ptr %retval + br label %ret +ifend7: + %t35 = load i32, ptr %t0 + %t36 = add i32 %t35, 1 + store i32 %t36, ptr %t0 + br label %wcond0 +wend2: + store i32 0, ptr %retval + br label %ret +ret: + %t37 = load i32, ptr %retval + ret i32 %t37 +} + +define i32 @fn_ui_index_of(ptr %arg_nm) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t6 = alloca ptr + %t7 = alloca i32 + %t8 = alloca i32 + %t9 = alloca i32 + %t17 = alloca i32 + %t79 = alloca ptr + %t86 = alloca i32 + store ptr %arg_nm, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = load ptr, ptr %t0 + %t3 = call i32 @fn_slen(ptr %t2) + %t4 = sub i32 %t3, 3 + %t5 = call ptr @fn_substr(ptr %t1, i32 3, i32 %t4) + store ptr %t5, ptr %t6 + store i32 0, ptr %t7 + store i32 0, ptr %t8 + store i32 0, ptr %t9 + br label %wcond0 +wcond0: + %t10 = load i32, ptr %t9 + %t11 = load ptr, ptr @g_prog + %t12 = getelementptr inbounds %LSlice, ptr %t11, i32 0, i32 1 + %t13 = load i32, ptr %t12 + %t14 = icmp slt i32 %t10, %t13 + %t15 = zext i1 %t14 to i32 + %t16 = icmp ne i32 %t15, 0 + br i1 %t16, label %wbody1, label %wend2 +wbody1: + %t18 = load ptr, ptr @g_prog + %t19 = getelementptr inbounds %LSlice, ptr %t18, i32 0, i32 0 + %t20 = load ptr, ptr %t19 + %t21 = load i32, ptr %t9 + %t22 = getelementptr inbounds ptr, ptr %t20, i32 %t21 + %t23 = load ptr, ptr %t22 + %t24 = getelementptr inbounds %Str_Node, ptr %t23, i32 0, i32 0 + %t25 = load i32, ptr %t24 + %t26 = icmp eq i32 %t25, 12 + %t27 = zext i1 %t26 to i32 + %t28 = icmp ne i32 %t27, 0 + %t29 = zext i1 %t28 to i32 + store i32 %t29, ptr %t17 + br i1 %t28, label %sc3, label %scend4 +sc3: + %t30 = load ptr, ptr @g_prog + %t31 = getelementptr inbounds %LSlice, ptr %t30, i32 0, i32 0 + %t32 = load ptr, ptr %t31 + %t33 = load i32, ptr %t9 + %t34 = getelementptr inbounds ptr, ptr %t32, i32 %t33 + %t35 = load ptr, ptr %t34 + %t36 = getelementptr inbounds %Str_Node, ptr %t35, i32 0, i32 2 + %t37 = load i32, ptr %t36 + %t38 = icmp eq i32 %t37, 1 + %t39 = zext i1 %t38 to i32 + %t40 = icmp ne i32 %t39, 0 + %t41 = zext i1 %t40 to i32 + store i32 %t41, ptr %t17 + br label %scend4 +scend4: + %t42 = load i32, ptr %t17 + %t43 = icmp ne i32 %t42, 0 + br i1 %t43, label %then5, label %ifend7 +then5: + %t44 = load ptr, ptr @g_prog + %t45 = getelementptr inbounds %LSlice, ptr %t44, i32 0, i32 0 + %t46 = load ptr, ptr %t45 + %t47 = load i32, ptr %t9 + %t48 = getelementptr inbounds ptr, ptr %t46, i32 %t47 + %t49 = load ptr, ptr %t48 + %t50 = getelementptr inbounds %Str_Node, ptr %t49, i32 0, i32 1 + %t51 = load ptr, ptr %t50 + %t52 = load ptr, ptr %t6 + %t53 = call i32 @fn_streq(ptr %t51, ptr %t52) + %t54 = icmp ne i32 %t53, 0 + br i1 %t54, label %then8, label %ifend10 +then8: + %t55 = load ptr, ptr @g_ui_roots + %t56 = getelementptr inbounds %LSlice, ptr %t55, i32 0, i32 0 + %t57 = load ptr, ptr %t56 + %t58 = load i32, ptr %t8 + %t59 = getelementptr inbounds i32, ptr %t57, i32 %t58 + %t60 = load i32, ptr %t59 + store i32 %t60, ptr %retval + br label %ret +ifend10: + %t61 = load i32, ptr %t8 + %t62 = add i32 %t61, 1 + store i32 %t62, ptr %t8 + br label %ifend7 +ifend7: + %t63 = load i32, ptr %t9 + %t64 = add i32 %t63, 1 + store i32 %t64, ptr %t9 + br label %wcond0 +wend2: + store i32 0, ptr %t9 + br label %wcond11 +wcond11: + %t65 = load i32, ptr %t9 + %t66 = load ptr, ptr @g_uiw + %t67 = getelementptr inbounds %LSlice, ptr %t66, i32 0, i32 1 + %t68 = load i32, ptr %t67 + %t69 = icmp slt i32 %t65, %t68 + %t70 = zext i1 %t69 to i32 + %t71 = icmp ne i32 %t70, 0 + br i1 %t71, label %wbody12, label %wend13 +wbody12: + %t72 = load ptr, ptr @g_uiw + %t73 = getelementptr inbounds %LSlice, ptr %t72, i32 0, i32 0 + %t74 = load ptr, ptr %t73 + %t75 = load i32, ptr %t9 + %t76 = getelementptr inbounds ptr, ptr %t74, i32 %t75 + %t77 = load ptr, ptr %t76 + %t78 = call ptr @fn_ui_prop(ptr %t77, ptr @.str1335) + store ptr %t78, ptr %t79 + %t80 = load ptr, ptr %t79 + %t81 = icmp eq ptr %t80, null + %t82 = zext i1 %t81 to i32 + %t83 = icmp eq i32 %t82, 0 + %t84 = zext i1 %t83 to i32 + %t85 = icmp ne i32 %t84, 0 + br i1 %t85, label %then14, label %ifend16 +then14: + %t87 = load ptr, ptr %t79 + %t88 = getelementptr inbounds %Str_Node, ptr %t87, i32 0, i32 0 + %t89 = load i32, ptr %t88 + %t90 = icmp eq i32 %t89, 33 + %t91 = zext i1 %t90 to i32 + %t92 = icmp ne i32 %t91, 0 + %t93 = zext i1 %t92 to i32 + store i32 %t93, ptr %t86 + br i1 %t92, label %sc17, label %scend18 +sc17: + %t94 = load ptr, ptr %t79 + %t95 = getelementptr inbounds %Str_Node, ptr %t94, i32 0, i32 1 + %t96 = load ptr, ptr %t95 + %t97 = load ptr, ptr %t6 + %t98 = call i32 @fn_streq(ptr %t96, ptr %t97) + %t99 = icmp ne i32 %t98, 0 + %t100 = zext i1 %t99 to i32 + store i32 %t100, ptr %t86 + br label %scend18 +scend18: + %t101 = load i32, ptr %t86 + %t102 = icmp ne i32 %t101, 0 + br i1 %t102, label %then19, label %ifend21 +then19: + %t103 = load i32, ptr %t9 + store i32 %t103, ptr %retval + br label %ret +ifend21: + br label %ifend16 +ifend16: + %t104 = load i32, ptr %t9 + %t105 = add i32 %t104, 1 + store i32 %t105, ptr %t9 + br label %wcond11 +wend13: + store i32 0, ptr %retval + br label %ret +ret: + %t106 = load i32, ptr %retval + ret i32 %t106 +} + +define i32 @fn_is_ui_ident(ptr %arg_nm) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca i32 + %t2 = alloca i32 + %t3 = alloca i32 + store ptr %arg_nm, ptr %t0 + %t4 = load ptr, ptr %t0 + %t5 = call i32 @fn_slen(ptr %t4) + %t6 = icmp sgt i32 %t5, 3 + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + %t9 = zext i1 %t8 to i32 + store i32 %t9, ptr %t3 + br i1 %t8, label %sc0, label %scend1 +sc0: + %t10 = load ptr, ptr %t0 + %t11 = getelementptr inbounds i8, ptr %t10, i32 0 + %t12 = load i8, ptr %t11 + %t13 = zext i8 %t12 to i32 + %t14 = icmp eq i32 %t13, 85 + %t15 = zext i1 %t14 to i32 + %t16 = icmp ne i32 %t15, 0 + %t17 = zext i1 %t16 to i32 + store i32 %t17, ptr %t3 + br label %scend1 +scend1: + %t18 = load i32, ptr %t3 + %t19 = icmp ne i32 %t18, 0 + %t20 = zext i1 %t19 to i32 + store i32 %t20, ptr %t2 + br i1 %t19, label %sc2, label %scend3 +sc2: + %t21 = load ptr, ptr %t0 + %t22 = getelementptr inbounds i8, ptr %t21, i32 1 + %t23 = load i8, ptr %t22 + %t24 = zext i8 %t23 to i32 + %t25 = icmp eq i32 %t24, 73 + %t26 = zext i1 %t25 to i32 + %t27 = icmp ne i32 %t26, 0 + %t28 = zext i1 %t27 to i32 + store i32 %t28, ptr %t2 + br label %scend3 +scend3: + %t29 = load i32, ptr %t2 + %t30 = icmp ne i32 %t29, 0 + %t31 = zext i1 %t30 to i32 + store i32 %t31, ptr %t1 + br i1 %t30, label %sc4, label %scend5 +sc4: + %t32 = load ptr, ptr %t0 + %t33 = getelementptr inbounds i8, ptr %t32, i32 2 + %t34 = load i8, ptr %t33 + %t35 = zext i8 %t34 to i32 + %t36 = icmp eq i32 %t35, 95 + %t37 = zext i1 %t36 to i32 + %t38 = icmp ne i32 %t37, 0 + %t39 = zext i1 %t38 to i32 + store i32 %t39, ptr %t1 + br label %scend5 +scend5: + %t40 = load i32, ptr %t1 + store i32 %t40, ptr %retval + br label %ret +ret: + %t41 = load i32, ptr %retval + ret i32 %t41 +} + +define void @fn_ll_ui_set(i32 %arg_idx, i32 %arg_key, ptr %arg_val) { +entry: + %t0 = alloca i32 + %t1 = alloca i32 + %t2 = alloca ptr + store i32 %arg_idx, ptr %t0 + store i32 %arg_key, ptr %t1 + store ptr %arg_val, ptr %t2 + call void @fn_emit(ptr @.str1336) + %t3 = load i32, ptr %t0 + %t4 = call ptr @fn_itoa(i32 %t3) + call void @fn_emit(ptr %t4) + call void @fn_emit(ptr @.str1337) + %t5 = load i32, ptr %t1 + %t6 = call ptr @fn_itoa(i32 %t5) + call void @fn_emit(ptr %t6) + call void @fn_emit(ptr @.str1338) + %t7 = load ptr, ptr %t2 + call void @fn_emit(ptr %t7) + call void @fn_emit(ptr @.str1339) + br label %ret +ret: + ret void +} + +define i32 @fn_ui_prop_key(ptr %arg_k) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + store ptr %arg_k, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_streq(ptr %t1, ptr @.str1340) + %t3 = icmp ne i32 %t2, 0 + br i1 %t3, label %then0, label %ifend2 +then0: + store i32 2, ptr %retval + br label %ret +ifend2: + %t4 = load ptr, ptr %t0 + %t5 = call i32 @fn_streq(ptr %t4, ptr @.str1341) + %t6 = icmp ne i32 %t5, 0 + br i1 %t6, label %then3, label %ifend5 +then3: + store i32 3, ptr %retval + br label %ret +ifend5: + %t7 = load ptr, ptr %t0 + %t8 = call i32 @fn_streq(ptr %t7, ptr @.str1342) + %t9 = icmp ne i32 %t8, 0 + br i1 %t9, label %then6, label %ifend8 +then6: + store i32 4, ptr %retval + br label %ret +ifend8: + %t10 = load ptr, ptr %t0 + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str1343) + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then9, label %ifend11 +then9: + store i32 5, ptr %retval + br label %ret +ifend11: + %t13 = load ptr, ptr %t0 + %t14 = call i32 @fn_streq(ptr %t13, ptr @.str1344) + %t15 = icmp ne i32 %t14, 0 + br i1 %t15, label %then12, label %ifend14 +then12: + store i32 7, ptr %retval + br label %ret +ifend14: + %t16 = load ptr, ptr %t0 + %t17 = call i32 @fn_streq(ptr %t16, ptr @.str1345) + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %then15, label %ifend17 +then15: + store i32 8, ptr %retval + br label %ret +ifend17: + %t19 = load ptr, ptr %t0 + %t20 = call i32 @fn_streq(ptr %t19, ptr @.str1346) + %t21 = icmp ne i32 %t20, 0 + br i1 %t21, label %then18, label %ifend20 +then18: + store i32 9, ptr %retval + br label %ret +ifend20: + %t22 = load ptr, ptr %t0 + %t23 = call i32 @fn_streq(ptr %t22, ptr @.str1347) + %t24 = icmp ne i32 %t23, 0 + br i1 %t24, label %then21, label %ifend23 +then21: + store i32 10, ptr %retval + br label %ret +ifend23: + %t25 = load ptr, ptr %t0 + %t26 = call i32 @fn_streq(ptr %t25, ptr @.str1348) + %t27 = icmp ne i32 %t26, 0 + br i1 %t27, label %then24, label %ifend26 +then24: + store i32 11, ptr %retval + br label %ret +ifend26: + %t28 = load ptr, ptr %t0 + %t29 = call i32 @fn_streq(ptr %t28, ptr @.str1349) + %t30 = icmp ne i32 %t29, 0 + br i1 %t30, label %then27, label %ifend29 +then27: + store i32 13, ptr %retval + br label %ret +ifend29: + %t31 = load ptr, ptr %t0 + %t32 = call i32 @fn_streq(ptr %t31, ptr @.str1350) + %t33 = icmp ne i32 %t32, 0 + br i1 %t33, label %then30, label %ifend32 +then30: + store i32 14, ptr %retval + br label %ret +ifend32: + %t34 = load ptr, ptr %t0 + %t35 = call i32 @fn_streq(ptr %t34, ptr @.str1351) + %t36 = icmp ne i32 %t35, 0 + br i1 %t36, label %then33, label %ifend35 +then33: + store i32 15, ptr %retval + br label %ret +ifend35: + %t37 = load ptr, ptr %t0 + %t38 = call i32 @fn_streq(ptr %t37, ptr @.str1352) + %t39 = icmp ne i32 %t38, 0 + br i1 %t39, label %then36, label %ifend38 +then36: + store i32 16, ptr %retval + br label %ret +ifend38: + %t40 = load ptr, ptr %t0 + %t41 = call i32 @fn_streq(ptr %t40, ptr @.str1353) + %t42 = icmp ne i32 %t41, 0 + br i1 %t42, label %then39, label %ifend41 +then39: + store i32 17, ptr %retval + br label %ret +ifend41: + %t43 = sub i32 0, 1 + store i32 %t43, ptr %retval + br label %ret +ret: + %t44 = load i32, ptr %retval + ret i32 %t44 +} + +define void @fn_emit_ui_build() { +entry: + %t1 = alloca ptr + %t4 = alloca ptr + %t10 = alloca i32 + %t24 = alloca ptr + %t27 = alloca i32 + %t44 = alloca i32 + %t66 = alloca ptr + %t70 = alloca ptr + %t74 = alloca ptr + %t85 = alloca ptr + %t91 = alloca i32 + %t104 = alloca ptr + %t111 = alloca ptr + %t128 = alloca i32 + %t144 = alloca ptr + %t151 = alloca i32 + %t158 = alloca ptr + %t164 = alloca i32 + call void @fn_ui_flatten_all() + store i32 0, ptr @g_ll_t + store i32 0, ptr @g_ll_lbl + store i32 0, ptr @g_g_term + call void @fn_loc_reset() + store i32 0, ptr @g_nloop + %t0 = call ptr @fn_buf_new() + store ptr %t0, ptr %t1 + %t2 = call ptr @fn_buf_new() + store ptr %t2, ptr @g_falloc + %t3 = load ptr, ptr @g_code + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t1 + store ptr %t5, ptr @g_code + call void @fn_emit(ptr @.str1354) + %t6 = load ptr, ptr @g_uiw + %t7 = getelementptr inbounds %LSlice, ptr %t6, i32 0, i32 1 + %t8 = load i32, ptr %t7 + %t9 = call ptr @fn_itoa(i32 %t8) + call void @fn_emit(ptr %t9) + call void @fn_emit(ptr @.str1355) + store i32 0, ptr %t10 + br label %wcond0 +wcond0: + %t11 = load i32, ptr %t10 + %t12 = load ptr, ptr @g_uiw + %t13 = getelementptr inbounds %LSlice, ptr %t12, i32 0, i32 1 + %t14 = load i32, ptr %t13 + %t15 = icmp slt i32 %t11, %t14 + %t16 = zext i1 %t15 to i32 + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %wbody1, label %wend2 +wbody1: + %t18 = load ptr, ptr @g_uiw + %t19 = getelementptr inbounds %LSlice, ptr %t18, i32 0, i32 0 + %t20 = load ptr, ptr %t19 + %t21 = load i32, ptr %t10 + %t22 = getelementptr inbounds ptr, ptr %t20, i32 %t21 + %t23 = load ptr, ptr %t22 + store ptr %t23, ptr %t24 + %t25 = load ptr, ptr %t24 + %t26 = call i32 @fn_ui_wtype(ptr %t25) + store i32 %t26, ptr %t27 + %t28 = load i32, ptr %t10 + %t29 = load i32, ptr %t27 + %t30 = call ptr @fn_itoa(i32 %t29) + call void @fn_ll_ui_set(i32 %t28, i32 0, ptr %t30) + %t31 = load i32, ptr %t10 + %t32 = load ptr, ptr @g_uiw_parent + %t33 = getelementptr inbounds %LSlice, ptr %t32, i32 0, i32 0 + %t34 = load ptr, ptr %t33 + %t35 = load i32, ptr %t10 + %t36 = getelementptr inbounds i32, ptr %t34, i32 %t35 + %t37 = load i32, ptr %t36 + %t38 = call ptr @fn_itoa(i32 %t37) + call void @fn_ll_ui_set(i32 %t31, i32 1, ptr %t38) + %t39 = load i32, ptr %t27 + %t40 = icmp eq i32 %t39, 4 + %t41 = zext i1 %t40 to i32 + %t42 = icmp ne i32 %t41, 0 + br i1 %t42, label %then3, label %ifend5 +then3: + %t43 = load i32, ptr %t10 + call void @fn_ll_ui_set(i32 %t43, i32 17, ptr @.str1356) + br label %ifend5 +ifend5: + store i32 0, ptr %t44 + br label %wcond6 +wcond6: + %t45 = load i32, ptr %t44 + %t46 = load ptr, ptr %t24 + %t47 = getelementptr inbounds %Str_Node, ptr %t46, i32 0, i32 5 + %t48 = load ptr, ptr %t47 + %t49 = getelementptr inbounds %Str_Node, ptr %t48, i32 0, i32 7 + %t50 = load ptr, ptr %t49 + %t51 = getelementptr inbounds %LSlice, ptr %t50, i32 0, i32 1 + %t52 = load i32, ptr %t51 + %t53 = icmp slt i32 %t45, %t52 + %t54 = zext i1 %t53 to i32 + %t55 = icmp ne i32 %t54, 0 + br i1 %t55, label %wbody7, label %wend8 +wbody7: + %t56 = load ptr, ptr %t24 + %t57 = getelementptr inbounds %Str_Node, ptr %t56, i32 0, i32 5 + %t58 = load ptr, ptr %t57 + %t59 = getelementptr inbounds %Str_Node, ptr %t58, i32 0, i32 7 + %t60 = load ptr, ptr %t59 + %t61 = getelementptr inbounds %LSlice, ptr %t60, i32 0, i32 0 + %t62 = load ptr, ptr %t61 + %t63 = load i32, ptr %t44 + %t64 = getelementptr inbounds ptr, ptr %t62, i32 %t63 + %t65 = load ptr, ptr %t64 + store ptr %t65, ptr %t66 + %t67 = load ptr, ptr %t66 + %t68 = getelementptr inbounds %Str_Node, ptr %t67, i32 0, i32 1 + %t69 = load ptr, ptr %t68 + store ptr %t69, ptr %t70 + %t71 = load ptr, ptr %t66 + %t72 = getelementptr inbounds %Str_Node, ptr %t71, i32 0, i32 4 + %t73 = load ptr, ptr %t72 + store ptr %t73, ptr %t74 + %t75 = load ptr, ptr %t70 + %t76 = call i32 @fn_streq(ptr %t75, ptr @.str1357) + %t77 = icmp ne i32 %t76, 0 + br i1 %t77, label %then9, label %ifend11 +then9: + %t78 = load i32, ptr %t44 + %t79 = add i32 %t78, 1 + store i32 %t79, ptr %t44 + br label %wcond6 +ifend11: + %t80 = load ptr, ptr %t70 + %t81 = call i32 @fn_streq(ptr %t80, ptr @.str1358) + %t82 = icmp ne i32 %t81, 0 + br i1 %t82, label %then12, label %else13 +then12: + %t83 = load ptr, ptr %t74 + %t84 = call ptr @fn_emit_expr(ptr %t83) + store ptr %t84, ptr %t85 + call void @fn_emit(ptr @.str1359) + %t86 = load i32, ptr %t10 + %t87 = call ptr @fn_itoa(i32 %t86) + call void @fn_emit(ptr %t87) + call void @fn_emit(ptr @.str1360) + %t88 = load ptr, ptr %t85 + %t89 = getelementptr inbounds %Str_Val, ptr %t88, i32 0, i32 0 + %t90 = load ptr, ptr %t89 + call void @fn_emit(ptr %t90) + call void @fn_emit(ptr @.str1361) + br label %ifend14 +else13: + %t92 = load ptr, ptr %t70 + %t93 = call i32 @fn_streq(ptr %t92, ptr @.str1362) + %t94 = icmp ne i32 %t93, 0 + %t95 = zext i1 %t94 to i32 + store i32 %t95, ptr %t91 + br i1 %t94, label %scend16, label %sc15 +sc15: + %t96 = load ptr, ptr %t70 + %t97 = call i32 @fn_streq(ptr %t96, ptr @.str1363) + %t98 = icmp ne i32 %t97, 0 + %t99 = zext i1 %t98 to i32 + store i32 %t99, ptr %t91 + br label %scend16 +scend16: + %t100 = load i32, ptr %t91 + %t101 = icmp ne i32 %t100, 0 + br i1 %t101, label %then17, label %else18 +then17: + %t102 = load ptr, ptr %t74 + %t103 = call ptr @fn_emit_expr(ptr %t102) + store ptr %t103, ptr %t104 + %t105 = load ptr, ptr %t104 + %t106 = getelementptr inbounds %Str_Val, ptr %t105, i32 0, i32 0 + %t107 = load ptr, ptr %t106 + %t108 = call ptr @fn_sconcat(ptr %t107, ptr @.str1365) + %t109 = call ptr @fn_sconcat(ptr @.str1364, ptr %t108) + %t110 = call ptr @fn_emit_bind(ptr %t109) + store ptr %t110, ptr %t111 + %t112 = load ptr, ptr %t70 + %t113 = call i32 @fn_streq(ptr %t112, ptr @.str1366) + %t114 = icmp ne i32 %t113, 0 + br i1 %t114, label %then20, label %else21 +then20: + %t115 = load i32, ptr %t10 + %t116 = load ptr, ptr %t111 + call void @fn_ll_ui_set(i32 %t115, i32 20, ptr %t116) + br label %ifend22 +else21: + %t117 = load i32, ptr %t10 + %t118 = load ptr, ptr %t111 + call void @fn_ll_ui_set(i32 %t117, i32 19, ptr %t118) + br label %ifend22 +ifend22: + br label %ifend19 +else18: + %t119 = load ptr, ptr %t70 + %t120 = call i32 @fn_streq(ptr %t119, ptr @.str1367) + %t121 = icmp ne i32 %t120, 0 + br i1 %t121, label %then23, label %else24 +then23: + %t122 = load ptr, ptr %t74 + %t123 = getelementptr inbounds %Str_Node, ptr %t122, i32 0, i32 0 + %t124 = load i32, ptr %t123 + %t125 = icmp eq i32 %t124, 33 + %t126 = zext i1 %t125 to i32 + %t127 = icmp ne i32 %t126, 0 + br i1 %t127, label %then26, label %else27 +then26: + store i32 0, ptr %t128 + %t129 = load ptr, ptr %t74 + %t130 = getelementptr inbounds %Str_Node, ptr %t129, i32 0, i32 1 + %t131 = load ptr, ptr %t130 + %t132 = call i32 @fn_streq(ptr %t131, ptr @.str1368) + %t133 = icmp ne i32 %t132, 0 + br i1 %t133, label %then29, label %ifend31 +then29: + store i32 1, ptr %t128 + br label %ifend31 +ifend31: + %t134 = load ptr, ptr %t74 + %t135 = getelementptr inbounds %Str_Node, ptr %t134, i32 0, i32 1 + %t136 = load ptr, ptr %t135 + %t137 = call i32 @fn_streq(ptr %t136, ptr @.str1369) + %t138 = icmp ne i32 %t137, 0 + br i1 %t138, label %then32, label %ifend34 +then32: + store i32 2, ptr %t128 + br label %ifend34 +ifend34: + %t139 = load i32, ptr %t10 + %t140 = load i32, ptr %t128 + %t141 = call ptr @fn_itoa(i32 %t140) + call void @fn_ll_ui_set(i32 %t139, i32 12, ptr %t141) + br label %ifend28 +else27: + %t142 = load ptr, ptr %t74 + %t143 = call ptr @fn_emit_expr(ptr %t142) + store ptr %t143, ptr %t144 + %t145 = load i32, ptr %t10 + %t146 = load ptr, ptr %t144 + %t147 = getelementptr inbounds %Str_Val, ptr %t146, i32 0, i32 0 + %t148 = load ptr, ptr %t147 + call void @fn_ll_ui_set(i32 %t145, i32 12, ptr %t148) + br label %ifend28 +ifend28: + br label %ifend25 +else24: + %t149 = load ptr, ptr %t70 + %t150 = call i32 @fn_ui_prop_key(ptr %t149) + store i32 %t150, ptr %t151 + %t152 = load i32, ptr %t151 + %t153 = icmp sge i32 %t152, 0 + %t154 = zext i1 %t153 to i32 + %t155 = icmp ne i32 %t154, 0 + br i1 %t155, label %then35, label %ifend37 +then35: + %t156 = load ptr, ptr %t74 + %t157 = call ptr @fn_emit_expr(ptr %t156) + store ptr %t157, ptr %t158 + %t159 = load i32, ptr %t10 + %t160 = load i32, ptr %t151 + %t161 = load ptr, ptr %t158 + %t162 = getelementptr inbounds %Str_Val, ptr %t161, i32 0, i32 0 + %t163 = load ptr, ptr %t162 + call void @fn_ll_ui_set(i32 %t159, i32 %t160, ptr %t163) + %t165 = load i32, ptr %t151 + %t166 = icmp eq i32 %t165, 4 + %t167 = zext i1 %t166 to i32 + %t168 = icmp ne i32 %t167, 0 + %t169 = zext i1 %t168 to i32 + store i32 %t169, ptr %t164 + br i1 %t168, label %scend39, label %sc38 +sc38: + %t170 = load i32, ptr %t151 + %t171 = icmp eq i32 %t170, 5 + %t172 = zext i1 %t171 to i32 + %t173 = icmp ne i32 %t172, 0 + %t174 = zext i1 %t173 to i32 + store i32 %t174, ptr %t164 + br label %scend39 +scend39: + %t175 = load i32, ptr %t164 + %t176 = icmp ne i32 %t175, 0 + br i1 %t176, label %then40, label %ifend42 +then40: + %t177 = load i32, ptr %t10 + call void @fn_ll_ui_set(i32 %t177, i32 6, ptr @.str1370) + br label %ifend42 +ifend42: + br label %ifend37 +ifend37: + br label %ifend25 +ifend25: + br label %ifend19 +ifend19: + br label %ifend14 +ifend14: + %t178 = load i32, ptr %t44 + %t179 = add i32 %t178, 1 + store i32 %t179, ptr %t44 + br label %wcond6 +wend8: + %t180 = load i32, ptr %t10 + %t181 = add i32 %t180, 1 + store i32 %t181, ptr %t10 + br label %wcond0 +wend2: + %t182 = load ptr, ptr %t4 + store ptr %t182, ptr @g_code + call void @fn_emit(ptr @.str1371) + %t183 = load ptr, ptr @g_falloc + %t184 = call ptr @fn_buf_str(ptr %t183) + call void @fn_emit(ptr %t184) + %t185 = load ptr, ptr %t1 + %t186 = call ptr @fn_buf_str(ptr %t185) + call void @fn_emit(ptr %t186) + call void @fn_emit(ptr @.str1372) + br label %ret +ret: + ret void +} + +define void @fn_emit_params_sig(ptr %arg_d) { +entry: + %t0 = alloca ptr + %t1 = alloca i32 + store ptr %arg_d, ptr %t0 + store i32 0, ptr %t1 + br label %wcond0 +wcond0: + %t2 = load i32, ptr %t1 + %t3 = load ptr, ptr %t0 + %t4 = getelementptr inbounds %Str_Node, ptr %t3, i32 0, i32 7 + %t5 = load ptr, ptr %t4 + %t6 = getelementptr inbounds %LSlice, ptr %t5, i32 0, i32 1 + %t7 = load i32, ptr %t6 + %t8 = icmp slt i32 %t2, %t7 + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %wbody1, label %wend2 +wbody1: + %t11 = load i32, ptr %t1 + %t12 = icmp sgt i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + %t14 = icmp ne i32 %t13, 0 + br i1 %t14, label %then3, label %ifend5 +then3: + call void @fn_emit(ptr @.str1373) + br label %ifend5 +ifend5: + %t15 = load ptr, ptr %t0 + %t16 = getelementptr inbounds %Str_Node, ptr %t15, i32 0, i32 7 + %t17 = load ptr, ptr %t16 + %t18 = getelementptr inbounds %LSlice, ptr %t17, i32 0, i32 0 + %t19 = load ptr, ptr %t18 + %t20 = load i32, ptr %t1 + %t21 = getelementptr inbounds ptr, ptr %t19, i32 %t20 + %t22 = load ptr, ptr %t21 + %t23 = getelementptr inbounds %Str_Node, ptr %t22, i32 0, i32 3 + %t24 = load ptr, ptr %t23 + %t25 = call ptr @fn_llty(ptr %t24) + call void @fn_emit(ptr %t25) + call void @fn_emit(ptr @.str1374) + %t26 = load ptr, ptr %t0 + %t27 = getelementptr inbounds %Str_Node, ptr %t26, i32 0, i32 7 + %t28 = load ptr, ptr %t27 + %t29 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 0 + %t30 = load ptr, ptr %t29 + %t31 = load i32, ptr %t1 + %t32 = getelementptr inbounds ptr, ptr %t30, i32 %t31 + %t33 = load ptr, ptr %t32 + %t34 = getelementptr inbounds %Str_Node, ptr %t33, i32 0, i32 1 + %t35 = load ptr, ptr %t34 + call void @fn_emit(ptr %t35) + %t36 = load i32, ptr %t1 + %t37 = add i32 %t36, 1 + store i32 %t37, ptr %t1 + br label %wcond0 +wend2: + br label %ret +ret: + ret void +} + +define void @fn_emit_fn(ptr %arg_d) { +entry: + %t0 = alloca ptr + %t5 = alloca ptr + %t8 = alloca ptr + %t12 = alloca ptr + %t22 = alloca i32 + %t40 = alloca ptr + %t46 = alloca ptr + %t78 = alloca ptr + store ptr %arg_d, ptr %t0 + store i32 0, ptr @g_ll_t + store i32 0, ptr @g_ll_lbl + store i32 0, ptr @g_g_term + call void @fn_loc_reset() + store i32 0, ptr @g_nloop + %t1 = load ptr, ptr %t0 + %t2 = getelementptr inbounds %Str_Node, ptr %t1, i32 0, i32 3 + %t3 = load ptr, ptr %t2 + store ptr %t3, ptr @g_ret_ty + %t4 = call ptr @fn_buf_new() + store ptr %t4, ptr %t5 + %t6 = call ptr @fn_buf_new() + store ptr %t6, ptr @g_falloc + %t7 = load ptr, ptr @g_code + store ptr %t7, ptr %t8 + %t9 = load ptr, ptr %t5 + store ptr %t9, ptr @g_code + %t10 = load ptr, ptr @g_ret_ty + %t11 = call ptr @fn_llty(ptr %t10) + store ptr %t11, ptr %t12 + %t13 = load ptr, ptr %t12 + %t14 = call i32 @fn_streq(ptr %t13, ptr @.str1375) + %t15 = icmp eq i32 %t14, 0 + %t16 = zext i1 %t15 to i32 + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %then0, label %ifend2 +then0: + %t18 = load ptr, ptr @g_falloc + call void @fn_buf_puts(ptr %t18, ptr @.str1376) + %t19 = load ptr, ptr @g_falloc + %t20 = load ptr, ptr %t12 + call void @fn_buf_puts(ptr %t19, ptr %t20) + %t21 = load ptr, ptr @g_falloc + call void @fn_buf_puts(ptr %t21, ptr @.str1377) + br label %ifend2 +ifend2: + store i32 0, ptr %t22 + br label %wcond3 +wcond3: + %t23 = load i32, ptr %t22 + %t24 = load ptr, ptr %t0 + %t25 = getelementptr inbounds %Str_Node, ptr %t24, i32 0, i32 7 + %t26 = load ptr, ptr %t25 + %t27 = getelementptr inbounds %LSlice, ptr %t26, i32 0, i32 1 + %t28 = load i32, ptr %t27 + %t29 = icmp slt i32 %t23, %t28 + %t30 = zext i1 %t29 to i32 + %t31 = icmp ne i32 %t30, 0 + br i1 %t31, label %wbody4, label %wend5 +wbody4: + %t32 = load ptr, ptr %t0 + %t33 = getelementptr inbounds %Str_Node, ptr %t32, i32 0, i32 7 + %t34 = load ptr, ptr %t33 + %t35 = getelementptr inbounds %LSlice, ptr %t34, i32 0, i32 0 + %t36 = load ptr, ptr %t35 + %t37 = load i32, ptr %t22 + %t38 = getelementptr inbounds ptr, ptr %t36, i32 %t37 + %t39 = load ptr, ptr %t38 + store ptr %t39, ptr %t40 + %t41 = load ptr, ptr %t40 + %t42 = getelementptr inbounds %Str_Node, ptr %t41, i32 0, i32 3 + %t43 = load ptr, ptr %t42 + %t44 = call ptr @fn_llty(ptr %t43) + %t45 = call ptr @fn_emit_alloca(ptr %t44) + store ptr %t45, ptr %t46 + call void @fn_emit(ptr @.str1378) + %t47 = load ptr, ptr %t40 + %t48 = getelementptr inbounds %Str_Node, ptr %t47, i32 0, i32 3 + %t49 = load ptr, ptr %t48 + %t50 = call ptr @fn_llty(ptr %t49) + call void @fn_emit(ptr %t50) + call void @fn_emit(ptr @.str1379) + %t51 = load ptr, ptr %t40 + %t52 = getelementptr inbounds %Str_Node, ptr %t51, i32 0, i32 1 + %t53 = load ptr, ptr %t52 + call void @fn_emit(ptr %t53) + call void @fn_emit(ptr @.str1380) + %t54 = load ptr, ptr %t46 + call void @fn_emit(ptr %t54) + call void @fn_emit(ptr @.str1381) + %t55 = load ptr, ptr %t40 + %t56 = getelementptr inbounds %Str_Node, ptr %t55, i32 0, i32 1 + %t57 = load ptr, ptr %t56 + %t58 = load ptr, ptr %t46 + %t59 = load ptr, ptr %t40 + %t60 = getelementptr inbounds %Str_Node, ptr %t59, i32 0, i32 3 + %t61 = load ptr, ptr %t60 + call void @fn_loc_push(ptr %t57, ptr %t58, ptr %t61) + %t62 = load i32, ptr %t22 + %t63 = add i32 %t62, 1 + store i32 %t63, ptr %t22 + br label %wcond3 +wend5: + %t64 = load ptr, ptr %t0 + %t65 = getelementptr inbounds %Str_Node, ptr %t64, i32 0, i32 4 + %t66 = load ptr, ptr %t65 + call void @fn_emit_block(ptr %t66) + %t67 = load i32, ptr @g_g_term + %t68 = icmp eq i32 %t67, 0 + %t69 = zext i1 %t68 to i32 + %t70 = icmp ne i32 %t69, 0 + br i1 %t70, label %then6, label %ifend8 +then6: + call void @fn_emit(ptr @.str1382) + br label %ifend8 +ifend8: + call void @fn_emit(ptr @.str1383) + %t71 = load ptr, ptr %t12 + %t72 = call i32 @fn_streq(ptr %t71, ptr @.str1384) + %t73 = icmp ne i32 %t72, 0 + br i1 %t73, label %then9, label %else10 +then9: + call void @fn_emit(ptr @.str1385) + br label %ifend11 +else10: + %t74 = load ptr, ptr %t12 + %t75 = call ptr @fn_sconcat(ptr %t74, ptr @.str1387) + %t76 = call ptr @fn_sconcat(ptr @.str1386, ptr %t75) + %t77 = call ptr @fn_emit_bind(ptr %t76) + store ptr %t77, ptr %t78 + call void @fn_emit(ptr @.str1388) + %t79 = load ptr, ptr %t12 + call void @fn_emit(ptr %t79) + call void @fn_emit(ptr @.str1389) + %t80 = load ptr, ptr %t78 + call void @fn_emit(ptr %t80) + call void @fn_emit(ptr @.str1390) + br label %ifend11 +ifend11: + %t81 = load ptr, ptr %t8 + store ptr %t81, ptr @g_code + call void @fn_emit(ptr @.str1391) + %t82 = load ptr, ptr %t12 + call void @fn_emit(ptr %t82) + call void @fn_emit(ptr @.str1392) + %t83 = load ptr, ptr %t0 + %t84 = getelementptr inbounds %Str_Node, ptr %t83, i32 0, i32 1 + %t85 = load ptr, ptr %t84 + call void @fn_emit(ptr %t85) + call void @fn_emit(ptr @.str1393) + %t86 = load ptr, ptr %t0 + call void @fn_emit_params_sig(ptr %t86) + call void @fn_emit(ptr @.str1394) + %t87 = load ptr, ptr @g_falloc + %t88 = call ptr @fn_buf_str(ptr %t87) + call void @fn_emit(ptr %t88) + %t89 = load ptr, ptr %t5 + %t90 = call ptr @fn_buf_str(ptr %t89) + call void @fn_emit(ptr %t90) + call void @fn_emit(ptr @.str1395) + br label %ret +ret: + ret void +} + +define void @fn_emit_main(ptr %arg_d) { +entry: + %t0 = alloca ptr + %t2 = alloca ptr + %t5 = alloca ptr + %t16 = alloca ptr + store ptr %arg_d, ptr %t0 + store i32 0, ptr @g_ll_t + store i32 0, ptr @g_ll_lbl + store i32 0, ptr @g_g_term + call void @fn_loc_reset() + store i32 0, ptr @g_nloop + store ptr @.str1396, ptr @g_ret_ty + %t1 = call ptr @fn_buf_new() + store ptr %t1, ptr %t2 + %t3 = call ptr @fn_buf_new() + store ptr %t3, ptr @g_falloc + %t4 = load ptr, ptr @g_code + store ptr %t4, ptr %t5 + %t6 = load ptr, ptr %t2 + store ptr %t6, ptr @g_code + %t7 = load ptr, ptr @g_falloc + call void @fn_buf_puts(ptr %t7, ptr @.str1397) + call void @fn_emit(ptr @.str1398) + call void @fn_emit(ptr @.str1399) + call void @fn_emit(ptr @.str1400) + %t8 = load ptr, ptr %t0 + %t9 = getelementptr inbounds %Str_Node, ptr %t8, i32 0, i32 4 + %t10 = load ptr, ptr %t9 + call void @fn_emit_block(ptr %t10) + %t11 = load i32, ptr @g_g_term + %t12 = icmp eq i32 %t11, 0 + %t13 = zext i1 %t12 to i32 + %t14 = icmp ne i32 %t13, 0 + br i1 %t14, label %then0, label %ifend2 +then0: + call void @fn_emit(ptr @.str1401) + br label %ifend2 +ifend2: + call void @fn_emit(ptr @.str1402) + %t15 = call ptr @fn_emit_bind(ptr @.str1403) + store ptr %t15, ptr %t16 + call void @fn_emit(ptr @.str1404) + %t17 = load ptr, ptr %t16 + call void @fn_emit(ptr %t17) + call void @fn_emit(ptr @.str1405) + %t18 = load ptr, ptr %t5 + store ptr %t18, ptr @g_code + call void @fn_emit(ptr @.str1406) + %t19 = load ptr, ptr @g_falloc + %t20 = call ptr @fn_buf_str(ptr %t19) + call void @fn_emit(ptr %t20) + %t21 = load ptr, ptr %t2 + %t22 = call ptr @fn_buf_str(ptr %t21) + call void @fn_emit(ptr %t22) + call void @fn_emit(ptr @.str1407) + br label %ret +ret: + ret void +} + +define void @fn_emit_program() { +entry: + %t46 = alloca i32 + %t0 = call ptr @fn_buf_new() + store ptr %t0, ptr @g_head + %t1 = call ptr @fn_buf_new() + store ptr %t1, ptr @g_code + %t2 = getelementptr %LSlice, ptr null, i32 1 + %t3 = ptrtoint ptr %t2 to i64 + %t4 = call ptr @malloc(i64 %t3) + %t5 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 0 + store ptr null, ptr %t5 + %t6 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 1 + store i32 0, ptr %t6 + %t7 = getelementptr inbounds %LSlice, ptr %t4, i32 0, i32 2 + store i32 0, ptr %t7 + store ptr %t4, ptr @g_loc_name + %t8 = getelementptr %LSlice, ptr null, i32 1 + %t9 = ptrtoint ptr %t8 to i64 + %t10 = call ptr @malloc(i64 %t9) + %t11 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 0 + store ptr null, ptr %t11 + %t12 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 1 + store i32 0, ptr %t12 + %t13 = getelementptr inbounds %LSlice, ptr %t10, i32 0, i32 2 + store i32 0, ptr %t13 + store ptr %t10, ptr @g_loc_reg + %t14 = getelementptr %LSlice, ptr null, i32 1 + %t15 = ptrtoint ptr %t14 to i64 + %t16 = call ptr @malloc(i64 %t15) + %t17 = getelementptr inbounds %LSlice, ptr %t16, i32 0, i32 0 + store ptr null, ptr %t17 + %t18 = getelementptr inbounds %LSlice, ptr %t16, i32 0, i32 1 + store i32 0, ptr %t18 + %t19 = getelementptr inbounds %LSlice, ptr %t16, i32 0, i32 2 + store i32 0, ptr %t19 + store ptr %t16, ptr @g_loc_ty + %t20 = getelementptr %LSlice, ptr null, i32 1 + %t21 = ptrtoint ptr %t20 to i64 + %t22 = call ptr @malloc(i64 %t21) + %t23 = getelementptr inbounds %LSlice, ptr %t22, i32 0, i32 0 + store ptr null, ptr %t23 + %t24 = getelementptr inbounds %LSlice, ptr %t22, i32 0, i32 1 + store i32 0, ptr %t24 + %t25 = getelementptr inbounds %LSlice, ptr %t22, i32 0, i32 2 + store i32 0, ptr %t25 + store ptr %t22, ptr @g_brk_lbl + %t26 = getelementptr %LSlice, ptr null, i32 1 + %t27 = ptrtoint ptr %t26 to i64 + %t28 = call ptr @malloc(i64 %t27) + %t29 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 0 + store ptr null, ptr %t29 + %t30 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 1 + store i32 0, ptr %t30 + %t31 = getelementptr inbounds %LSlice, ptr %t28, i32 0, i32 2 + store i32 0, ptr %t31 + store ptr %t28, ptr @g_cnt_lbl + %t32 = getelementptr %LSlice, ptr null, i32 1 + %t33 = ptrtoint ptr %t32 to i64 + %t34 = call ptr @malloc(i64 %t33) + %t35 = getelementptr inbounds %LSlice, ptr %t34, i32 0, i32 0 + store ptr null, ptr %t35 + %t36 = getelementptr inbounds %LSlice, ptr %t34, i32 0, i32 1 + store i32 0, ptr %t36 + %t37 = getelementptr inbounds %LSlice, ptr %t34, i32 0, i32 2 + store i32 0, ptr %t37 + store ptr %t34, ptr @g_self_stk + %t38 = getelementptr %LSlice, ptr null, i32 1 + %t39 = ptrtoint ptr %t38 to i64 + %t40 = call ptr @malloc(i64 %t39) + %t41 = getelementptr inbounds %LSlice, ptr %t40, i32 0, i32 0 + store ptr null, ptr %t41 + %t42 = getelementptr inbounds %LSlice, ptr %t40, i32 0, i32 1 + store i32 0, ptr %t42 + %t43 = getelementptr inbounds %LSlice, ptr %t40, i32 0, i32 2 + store i32 0, ptr %t43 + store ptr %t40, ptr @g_mach_stk + call void @fn_emit_header() + %t44 = call i32 @fn_has_ecs() + %t45 = icmp ne i32 %t44, 0 + br i1 %t45, label %then0, label %ifend2 +then0: + call void @fn_emit_ecs_storage() + br label %ifend2 +ifend2: + store i32 0, ptr %t46 + br label %wcond3 +wcond3: + %t47 = load i32, ptr %t46 + %t48 = load ptr, ptr @g_prog + %t49 = getelementptr inbounds %LSlice, ptr %t48, i32 0, i32 1 + %t50 = load i32, ptr %t49 + %t51 = icmp slt i32 %t47, %t50 + %t52 = zext i1 %t51 to i32 + %t53 = icmp ne i32 %t52, 0 + br i1 %t53, label %wbody4, label %wend5 +wbody4: + %t54 = load ptr, ptr @g_prog + %t55 = getelementptr inbounds %LSlice, ptr %t54, i32 0, i32 0 + %t56 = load ptr, ptr %t55 + %t57 = load i32, ptr %t46 + %t58 = getelementptr inbounds ptr, ptr %t56, i32 %t57 + %t59 = load ptr, ptr %t58 + %t60 = getelementptr inbounds %Str_Node, ptr %t59, i32 0, i32 0 + %t61 = load i32, ptr %t60 + %t62 = icmp eq i32 %t61, 4 + %t63 = zext i1 %t62 to i32 + %t64 = icmp ne i32 %t63, 0 + br i1 %t64, label %then6, label %ifend8 +then6: + %t65 = load ptr, ptr @g_prog + %t66 = getelementptr inbounds %LSlice, ptr %t65, i32 0, i32 0 + %t67 = load ptr, ptr %t66 + %t68 = load i32, ptr %t46 + %t69 = getelementptr inbounds ptr, ptr %t67, i32 %t68 + %t70 = load ptr, ptr %t69 + call void @fn_emit_fn(ptr %t70) + br label %ifend8 +ifend8: + %t71 = load i32, ptr %t46 + %t72 = add i32 %t71, 1 + store i32 %t72, ptr %t46 + br label %wcond3 +wend5: + %t73 = call i32 @fn_has_ecs() + %t74 = icmp ne i32 %t73, 0 + br i1 %t74, label %then9, label %ifend11 +then9: + call void @fn_emit_ecs_allocator() + call void @fn_emit_snapshot() + br label %ifend11 +ifend11: + %t75 = call i32 @fn_has_ui() + %t76 = icmp ne i32 %t75, 0 + br i1 %t76, label %then12, label %ifend14 +then12: + call void @fn_emit_ui_build() + br label %ifend14 +ifend14: + %t77 = call i32 @fn_has_systems() + %t78 = icmp ne i32 %t77, 0 + br i1 %t78, label %then15, label %else16 +then15: + call void @fn_emit_game_main() + br label %ifend17 +else16: + store i32 0, ptr %t46 + br label %wcond18 +wcond18: + %t79 = load i32, ptr %t46 + %t80 = load ptr, ptr @g_prog + %t81 = getelementptr inbounds %LSlice, ptr %t80, i32 0, i32 1 + %t82 = load i32, ptr %t81 + %t83 = icmp slt i32 %t79, %t82 + %t84 = zext i1 %t83 to i32 + %t85 = icmp ne i32 %t84, 0 + br i1 %t85, label %wbody19, label %wend20 +wbody19: + %t86 = load ptr, ptr @g_prog + %t87 = getelementptr inbounds %LSlice, ptr %t86, i32 0, i32 0 + %t88 = load ptr, ptr %t87 + %t89 = load i32, ptr %t46 + %t90 = getelementptr inbounds ptr, ptr %t88, i32 %t89 + %t91 = load ptr, ptr %t90 + %t92 = getelementptr inbounds %Str_Node, ptr %t91, i32 0, i32 0 + %t93 = load i32, ptr %t92 + %t94 = icmp eq i32 %t93, 6 + %t95 = zext i1 %t94 to i32 + %t96 = icmp ne i32 %t95, 0 + br i1 %t96, label %then21, label %ifend23 +then21: + %t97 = load ptr, ptr @g_prog + %t98 = getelementptr inbounds %LSlice, ptr %t97, i32 0, i32 0 + %t99 = load ptr, ptr %t98 + %t100 = load i32, ptr %t46 + %t101 = getelementptr inbounds ptr, ptr %t99, i32 %t100 + %t102 = load ptr, ptr %t101 + call void @fn_emit_main(ptr %t102) + br label %ifend23 +ifend23: + %t103 = load i32, ptr %t46 + %t104 = add i32 %t103, 1 + store i32 %t104, ptr %t46 + br label %wcond18 +wend20: + br label %ifend17 +ifend17: + br label %ret +ret: + ret void +} + +define i32 @fn_ir_flush(ptr %arg_path) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t3 = alloca ptr + %t6 = alloca ptr + %t15 = alloca ptr + store ptr %arg_path, ptr %t0 + %t1 = load ptr, ptr @g_head + %t2 = call ptr @fn_buf_str(ptr %t1) + store ptr %t2, ptr %t3 + %t4 = load ptr, ptr @g_code + %t5 = call ptr @fn_buf_str(ptr %t4) + store ptr %t5, ptr %t6 + %t7 = load ptr, ptr %t0 + %t8 = icmp eq ptr %t7, null + %t9 = zext i1 %t8 to i32 + %t10 = icmp ne i32 %t9, 0 + br i1 %t10, label %then0, label %ifend2 +then0: + %t11 = load ptr, ptr %t3 + call i32 (ptr, ...) @printf(ptr @.fmt_str, ptr %t11) + %t12 = load ptr, ptr %t6 + call i32 (ptr, ...) @printf(ptr @.fmt_str, ptr %t12) + store i32 1, ptr %retval + br label %ret +ifend2: + %t13 = load ptr, ptr %t0 + %t14 = call ptr @fopen(ptr %t13, ptr @.str1408) + store ptr %t14, ptr %t15 + %t16 = load ptr, ptr %t15 + %t17 = icmp eq ptr %t16, null + %t18 = zext i1 %t17 to i32 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then3, label %ifend5 +then3: + store i32 0, ptr %retval + br label %ret +ifend5: + %t20 = load ptr, ptr %t15 + %t21 = load ptr, ptr %t3 + %t22 = load ptr, ptr %t3 + %t23 = call i32 @fn_slen(ptr %t22) + %t24 = zext i32 %t23 to i64 + %t25 = call i64 @fwrite(ptr %t21, i64 1, i64 %t24, ptr %t20) + %t26 = trunc i64 %t25 to i32 + %t27 = load ptr, ptr %t15 + %t28 = load ptr, ptr %t6 + %t29 = load ptr, ptr %t6 + %t30 = call i32 @fn_slen(ptr %t29) + %t31 = zext i32 %t30 to i64 + %t32 = call i64 @fwrite(ptr %t28, i64 1, i64 %t31, ptr %t27) + %t33 = trunc i64 %t32 to i32 + %t34 = load ptr, ptr %t15 + call i32 @fclose(ptr %t34) + store i32 1, ptr %retval + br label %ret +ret: + %t35 = load i32, ptr %retval + ret i32 %t35 +} + +define ptr @fn_base_name(ptr %arg_path) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t2 = alloca i32 + %t3 = alloca i32 + store ptr %arg_path, ptr %t0 + %t1 = sub i32 0, 1 + store i32 %t1, ptr %t2 + store i32 0, ptr %t3 + br label %wcond0 +wcond0: + %t4 = load ptr, ptr %t0 + %t5 = load i32, ptr %t3 + %t6 = getelementptr inbounds i8, ptr %t4, i32 %t5 + %t7 = load i8, ptr %t6 + %t8 = zext i8 %t7 to i32 + %t9 = icmp ne i32 %t8, 0 + %t10 = zext i1 %t9 to i32 + %t11 = icmp ne i32 %t10, 0 + br i1 %t11, label %wbody1, label %wend2 +wbody1: + %t12 = load ptr, ptr %t0 + %t13 = load i32, ptr %t3 + %t14 = getelementptr inbounds i8, ptr %t12, i32 %t13 + %t15 = load i8, ptr %t14 + %t16 = zext i8 %t15 to i32 + %t17 = icmp eq i32 %t16, 47 + %t18 = zext i1 %t17 to i32 + %t19 = icmp ne i32 %t18, 0 + br i1 %t19, label %then3, label %ifend5 +then3: + %t20 = load i32, ptr %t3 + store i32 %t20, ptr %t2 + br label %ifend5 +ifend5: + %t21 = load i32, ptr %t3 + %t22 = add i32 %t21, 1 + store i32 %t22, ptr %t3 + br label %wcond0 +wend2: + %t23 = load ptr, ptr %t0 + %t24 = load i32, ptr %t2 + %t25 = add i32 %t24, 1 + %t26 = load i32, ptr %t3 + %t27 = load i32, ptr %t2 + %t28 = add i32 %t27, 1 + %t29 = sub i32 %t26, %t28 + %t30 = call ptr @fn_substr(ptr %t23, i32 %t25, i32 %t29) + store ptr %t30, ptr %retval + br label %ret +ret: + %t31 = load ptr, ptr %retval + ret ptr %t31 +} + +define ptr @fn_strip_ludic(ptr %arg_name) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t3 = alloca i32 + store ptr %arg_name, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_slen(ptr %t1) + store i32 %t2, ptr %t3 + %t4 = load i32, ptr %t3 + %t5 = icmp sgt i32 %t4, 6 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + %t8 = load ptr, ptr %t0 + %t9 = load i32, ptr %t3 + %t10 = sub i32 %t9, 6 + %t11 = call ptr @fn_substr(ptr %t8, i32 %t10, i32 6) + %t12 = call i32 @fn_streq(ptr %t11, ptr @.str1409) + %t13 = icmp ne i32 %t12, 0 + br i1 %t13, label %then3, label %ifend5 +then3: + %t14 = load ptr, ptr %t0 + %t15 = load i32, ptr %t3 + %t16 = sub i32 %t15, 6 + %t17 = call ptr @fn_substr(ptr %t14, i32 0, i32 %t16) + store ptr %t17, ptr %retval + br label %ret +ifend5: + br label %ifend2 +ifend2: + %t18 = load ptr, ptr %t0 + store ptr %t18, ptr %retval + br label %ret +ret: + %t19 = load ptr, ptr %retval + ret ptr %t19 +} + +define ptr @fn_getenv_or(ptr %arg_name, ptr %arg_dflt) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t1 = alloca ptr + %t4 = alloca ptr + store ptr %arg_name, ptr %t0 + store ptr %arg_dflt, ptr %t1 + %t2 = load ptr, ptr %t0 + %t3 = call ptr @getenv(ptr %t2) + store ptr %t3, ptr %t4 + %t5 = load ptr, ptr %t4 + %t6 = icmp eq ptr %t5, null + %t7 = zext i1 %t6 to i32 + %t8 = icmp ne i32 %t7, 0 + br i1 %t8, label %then0, label %ifend2 +then0: + %t9 = load ptr, ptr %t1 + store ptr %t9, ptr %retval + br label %ret +ifend2: + %t10 = load ptr, ptr %t4 + store ptr %t10, ptr %retval + br label %ret +ret: + %t11 = load ptr, ptr %retval + ret ptr %t11 +} + +define ptr @fn_ensure_slash(ptr %arg_d) { +entry: + %retval = alloca ptr + %t0 = alloca ptr + %t3 = alloca i32 + store ptr %arg_d, ptr %t0 + %t1 = load ptr, ptr %t0 + %t2 = call i32 @fn_slen(ptr %t1) + store i32 %t2, ptr %t3 + %t4 = load i32, ptr %t3 + %t5 = icmp eq i32 %t4, 0 + %t6 = zext i1 %t5 to i32 + %t7 = icmp ne i32 %t6, 0 + br i1 %t7, label %then0, label %ifend2 +then0: + %t8 = load ptr, ptr %t0 + store ptr %t8, ptr %retval + br label %ret +ifend2: + %t9 = load ptr, ptr %t0 + %t10 = load i32, ptr %t3 + %t11 = sub i32 %t10, 1 + %t12 = getelementptr inbounds i8, ptr %t9, i32 %t11 + %t13 = load i8, ptr %t12 + %t14 = zext i8 %t13 to i32 + %t15 = icmp eq i32 %t14, 47 + %t16 = zext i1 %t15 to i32 + %t17 = icmp ne i32 %t16, 0 + br i1 %t17, label %then3, label %ifend5 +then3: + %t18 = load ptr, ptr %t0 + store ptr %t18, ptr %retval + br label %ret +ifend5: + %t19 = load ptr, ptr %t0 + %t20 = call ptr @fn_sconcat(ptr %t19, ptr @.str1410) + store ptr %t20, ptr %retval + br label %ret +ret: + %t21 = load ptr, ptr %retval + ret ptr %t21 +} + +define void @fn_die(ptr %arg_msg) { +entry: + %t0 = alloca ptr + store ptr %arg_msg, ptr %t0 + %t1 = load ptr, ptr @__stderrp + %t2 = load ptr, ptr %t0 + %t3 = load ptr, ptr %t0 + %t4 = call i32 @fn_slen(ptr %t3) + %t5 = zext i32 %t4 to i64 + %t6 = call i64 @fwrite(ptr %t2, i64 1, i64 %t5, ptr %t1) + %t7 = trunc i64 %t6 to i32 + call void @exit(i32 1) + unreachable +ret: + ret void +} + +define i32 @main(i32 %argc, ptr %argv) { +entry: + %retval = alloca i32 + %t0 = alloca ptr + %t1 = alloca ptr + %t2 = alloca i32 + %t3 = alloca i32 + %t4 = alloca i32 + %t5 = alloca i32 + %t6 = alloca i32 + %t13 = alloca i32 + %t23 = alloca ptr + %t66 = alloca ptr + %t83 = alloca ptr + %t93 = alloca i32 + %t105 = alloca i32 + %t114 = alloca i32 + %t131 = alloca i32 + %t148 = alloca ptr + %t159 = alloca ptr + %t166 = alloca ptr + %t173 = alloca ptr + %t178 = alloca ptr + %t183 = alloca ptr + %t195 = alloca i32 + %t211 = alloca i32 + store i32 %argc, ptr @L_argc + store ptr %argv, ptr @L_argv + store i32 0, ptr %retval + store ptr null, ptr %t0 + store ptr null, ptr %t1 + store i32 0, ptr %t2 + store i32 0, ptr %t3 + store i32 0, ptr %t4 + store i32 0, ptr %t5 + store i32 0, ptr %t6 + %t7 = load ptr, ptr @L_argv + %t8 = getelementptr ptr, ptr %t7, i32 0 + %t9 = load ptr, ptr %t8 + %t10 = call ptr @fn_base_name(ptr %t9) + %t11 = call i32 @fn_streq(ptr %t10, ptr @.str1411) + %t12 = icmp ne i32 %t11, 0 + br i1 %t12, label %then0, label %ifend2 +then0: + store i32 1, ptr %t6 + br label %ifend2 +ifend2: + store i32 1, ptr %t13 + br label %wcond3 +wcond3: + %t14 = load i32, ptr %t13 + %t15 = load i32, ptr @L_argc + %t16 = icmp slt i32 %t14, %t15 + %t17 = zext i1 %t16 to i32 + %t18 = icmp ne i32 %t17, 0 + br i1 %t18, label %wbody4, label %wend5 +wbody4: + %t19 = load i32, ptr %t13 + %t20 = load ptr, ptr @L_argv + %t21 = getelementptr ptr, ptr %t20, i32 %t19 + %t22 = load ptr, ptr %t21 + store ptr %t22, ptr %t23 + %t24 = load ptr, ptr %t23 + %t25 = call i32 @fn_streq(ptr %t24, ptr @.str1412) + %t26 = icmp ne i32 %t25, 0 + br i1 %t26, label %then6, label %else7 +then6: + store i32 1, ptr %t2 + br label %ifend8 +else7: + %t27 = load ptr, ptr %t23 + %t28 = call i32 @fn_streq(ptr %t27, ptr @.str1413) + %t29 = icmp ne i32 %t28, 0 + br i1 %t29, label %then9, label %else10 +then9: + store i32 2, ptr %t2 + br label %ifend11 +else10: + %t30 = load ptr, ptr %t23 + %t31 = call i32 @fn_streq(ptr %t30, ptr @.str1414) + %t32 = icmp ne i32 %t31, 0 + br i1 %t32, label %then12, label %else13 +then12: + store i32 1, ptr %t3 + br label %ifend14 +else13: + %t33 = load ptr, ptr %t23 + %t34 = call i32 @fn_streq(ptr %t33, ptr @.str1415) + %t35 = icmp ne i32 %t34, 0 + br i1 %t35, label %then15, label %else16 +then15: + store i32 1, ptr %t4 + br label %ifend17 +else16: + %t36 = load ptr, ptr %t23 + %t37 = call i32 @fn_streq(ptr %t36, ptr @.str1416) + %t38 = icmp ne i32 %t37, 0 + br i1 %t38, label %then18, label %else19 +then18: + store i32 1, ptr %t5 + br label %ifend20 +else19: + %t39 = load ptr, ptr %t23 + %t40 = call i32 @fn_streq(ptr %t39, ptr @.str1417) + %t41 = icmp ne i32 %t40, 0 + br i1 %t41, label %then21, label %else22 +then21: + store i32 1, ptr %t6 + br label %ifend23 +else22: + %t42 = load ptr, ptr %t23 + %t43 = call i32 @fn_streq(ptr %t42, ptr @.str1418) + %t44 = icmp ne i32 %t43, 0 + br i1 %t44, label %then24, label %else25 +then24: + %t45 = load i32, ptr %t13 + %t46 = add i32 %t45, 1 + store i32 %t46, ptr %t13 + %t47 = load i32, ptr %t13 + %t48 = load i32, ptr @L_argc + %t49 = icmp slt i32 %t47, %t48 + %t50 = zext i1 %t49 to i32 + %t51 = icmp ne i32 %t50, 0 + br i1 %t51, label %then27, label %ifend29 +then27: + %t52 = load i32, ptr %t13 + %t53 = load ptr, ptr @L_argv + %t54 = getelementptr ptr, ptr %t53, i32 %t52 + %t55 = load ptr, ptr %t54 + store ptr %t55, ptr %t1 + br label %ifend29 +ifend29: + br label %ifend26 +else25: + %t56 = load ptr, ptr %t23 + %t57 = getelementptr inbounds i8, ptr %t56, i32 0 + %t58 = load i8, ptr %t57 + %t59 = zext i8 %t58 to i32 + %t60 = icmp eq i32 %t59, 45 + %t61 = zext i1 %t60 to i32 + %t62 = icmp ne i32 %t61, 0 + br i1 %t62, label %then30, label %else31 +then30: + %t63 = load ptr, ptr %t23 + %t64 = call ptr @fn_sconcat(ptr %t63, ptr @.str1420) + %t65 = call ptr @fn_sconcat(ptr @.str1419, ptr %t64) + store ptr %t65, ptr %t66 + %t67 = load ptr, ptr @__stderrp + %t68 = load ptr, ptr %t66 + %t69 = load ptr, ptr %t66 + %t70 = call i32 @fn_slen(ptr %t69) + %t71 = zext i32 %t70 to i64 + %t72 = call i64 @fwrite(ptr %t68, i64 1, i64 %t71, ptr %t67) + %t73 = trunc i64 %t72 to i32 + br label %ifend32 +else31: + %t74 = load ptr, ptr %t23 + store ptr %t74, ptr %t0 + br label %ifend32 +ifend32: + br label %ifend26 +ifend26: + br label %ifend23 +ifend23: + br label %ifend20 +ifend20: + br label %ifend17 +ifend17: + br label %ifend14 +ifend14: + br label %ifend11 +ifend11: + br label %ifend8 +ifend8: + %t75 = load i32, ptr %t13 + %t76 = add i32 %t75, 1 + store i32 %t76, ptr %t13 + br label %wcond3 +wend5: + %t77 = load ptr, ptr %t0 + %t78 = icmp eq ptr %t77, null + %t79 = zext i1 %t78 to i32 + %t80 = icmp ne i32 %t79, 0 + br i1 %t80, label %then33, label %ifend35 +then33: + call void @fn_die(ptr @.str1421) + br label %ifend35 +ifend35: + %t81 = load ptr, ptr %t0 + %t82 = call ptr @fn_read_file(ptr %t81) + store ptr %t82, ptr %t83 + %t84 = load ptr, ptr %t83 + %t85 = icmp eq ptr %t84, null + %t86 = zext i1 %t85 to i32 + %t87 = icmp ne i32 %t86, 0 + br i1 %t87, label %then36, label %ifend38 +then36: + call void @fn_die(ptr @.str1422) + br label %ifend38 +ifend38: + %t88 = load ptr, ptr %t0 + %t89 = call ptr @fn_dir_of(ptr %t88) + store ptr %t89, ptr @g_cur_dir + %t90 = load ptr, ptr %t83 + call void @fn_lex(ptr %t90) + call void @fn_parse_program() + %t91 = load i32, ptr %t4 + %t92 = icmp ne i32 %t91, 0 + br i1 %t92, label %then39, label %ifend41 +then39: + call void @exit(i32 0) + unreachable +ifend41: + call void @fn_maybe_splice_runtime() + %t94 = load i32, ptr %t6 + %t95 = icmp ne i32 %t94, 0 + %t96 = zext i1 %t95 to i32 + store i32 %t96, ptr %t93 + br i1 %t95, label %scend43, label %sc42 +sc42: + %t97 = load ptr, ptr %t1 + %t98 = icmp eq ptr %t97, null + %t99 = zext i1 %t98 to i32 + %t100 = icmp eq i32 %t99, 0 + %t101 = zext i1 %t100 to i32 + %t102 = icmp ne i32 %t101, 0 + %t103 = zext i1 %t102 to i32 + store i32 %t103, ptr %t93 + br label %scend43 +scend43: + %t104 = load i32, ptr %t93 + store i32 %t104, ptr %t105 + %t106 = load i32, ptr %t2 + %t107 = icmp eq i32 %t106, 1 + %t108 = zext i1 %t107 to i32 + %t109 = icmp ne i32 %t108, 0 + br i1 %t109, label %then44, label %else45 +then44: + store i32 1, ptr @g_g_windowed + br label %ifend46 +else45: + %t110 = load i32, ptr %t2 + %t111 = icmp eq i32 %t110, 2 + %t112 = zext i1 %t111 to i32 + %t113 = icmp ne i32 %t112, 0 + br i1 %t113, label %then47, label %else48 +then47: + store i32 0, ptr @g_g_windowed + br label %ifend49 +else48: + %t115 = load i32, ptr %t105 + %t116 = icmp ne i32 %t115, 0 + %t117 = zext i1 %t116 to i32 + store i32 %t117, ptr %t114 + br i1 %t116, label %sc50, label %scend51 +sc50: + %t118 = call i32 @fn_has_systems() + %t119 = icmp ne i32 %t118, 0 + %t120 = zext i1 %t119 to i32 + store i32 %t120, ptr %t114 + br label %scend51 +scend51: + %t121 = load i32, ptr %t114 + store i32 %t121, ptr @g_g_windowed + br label %ifend49 +ifend49: + br label %ifend46 +ifend46: + call void @fn_emit_program() + %t122 = load i32, ptr %t3 + %t123 = icmp ne i32 %t122, 0 + br i1 %t123, label %then52, label %ifend54 +then52: + %t124 = load ptr, ptr %t1 + %t125 = call i32 @fn_ir_flush(ptr %t124) + br label %ret +ifend54: + %t126 = load i32, ptr %t105 + %t127 = icmp eq i32 %t126, 0 + %t128 = zext i1 %t127 to i32 + %t129 = icmp ne i32 %t128, 0 + br i1 %t129, label %then55, label %ifend57 +then55: + %t130 = call i32 @fn_ir_flush(ptr null) + br label %ret +ifend57: + %t132 = load i32, ptr %t6 + %t133 = icmp ne i32 %t132, 0 + %t134 = zext i1 %t133 to i32 + store i32 %t134, ptr %t131 + br i1 %t133, label %sc58, label %scend59 +sc58: + %t135 = load ptr, ptr %t1 + %t136 = icmp eq ptr %t135, null + %t137 = zext i1 %t136 to i32 + %t138 = icmp ne i32 %t137, 0 + %t139 = zext i1 %t138 to i32 + store i32 %t139, ptr %t131 + br label %scend59 +scend59: + %t140 = load i32, ptr %t131 + %t141 = icmp ne i32 %t140, 0 + br i1 %t141, label %then60, label %ifend62 +then60: + %t142 = load ptr, ptr %t0 + %t143 = call ptr @fn_base_name(ptr %t142) + %t144 = call ptr @fn_strip_ludic(ptr %t143) + %t145 = call ptr @fn_sconcat(ptr @.str1423, ptr %t144) + store ptr %t145, ptr %t1 + br label %ifend62 +ifend62: + %t146 = load ptr, ptr %t1 + %t147 = call ptr @fn_dir_of(ptr %t146) + store ptr %t147, ptr %t148 + %t149 = load ptr, ptr %t148 + %t150 = call i32 @fn_slen(ptr %t149) + %t151 = icmp sgt i32 %t150, 0 + %t152 = zext i1 %t151 to i32 + %t153 = icmp ne i32 %t152, 0 + br i1 %t153, label %then63, label %ifend65 +then63: + %t154 = load ptr, ptr %t148 + %t155 = call ptr @fn_sconcat(ptr @.str1424, ptr %t154) + %t156 = call i32 @system(ptr %t155) + br label %ifend65 +ifend65: + %t157 = load ptr, ptr %t1 + %t158 = call ptr @fn_sconcat(ptr %t157, ptr @.str1425) + store ptr %t158, ptr %t159 + %t160 = load ptr, ptr %t159 + %t161 = call i32 @fn_ir_flush(ptr %t160) + %t162 = icmp eq i32 %t161, 0 + %t163 = zext i1 %t162 to i32 + %t164 = icmp ne i32 %t163, 0 + br i1 %t164, label %then66, label %ifend68 +then66: + call void @fn_die(ptr @.str1426) + br label %ifend68 +ifend68: + %t165 = call ptr @fn_getenv_or(ptr @.str1427, ptr @.str1428) + store ptr %t165, ptr %t166 + %t167 = load ptr, ptr @L_argv + %t168 = getelementptr ptr, ptr %t167, i32 0 + %t169 = load ptr, ptr %t168 + %t170 = call ptr @fn_dir_of(ptr %t169) + %t171 = call ptr @fn_getenv_or(ptr @.str1429, ptr %t170) + %t172 = call ptr @fn_ensure_slash(ptr %t171) + store ptr %t172, ptr %t173 + %t174 = load ptr, ptr %t166 + %t175 = load ptr, ptr %t159 + %t176 = call ptr @fn_sconcat(ptr @.str1430, ptr %t175) + %t177 = call ptr @fn_sconcat(ptr %t174, ptr %t176) + store ptr %t177, ptr %t178 + %t179 = load i32, ptr @g_g_windowed + %t180 = icmp ne i32 %t179, 0 + br i1 %t180, label %then69, label %ifend71 +then69: + %t181 = load ptr, ptr %t173 + %t182 = call ptr @fn_path_join(ptr %t181, ptr @.str1431) + store ptr %t182, ptr %t183 + %t184 = load ptr, ptr %t178 + %t185 = load ptr, ptr %t183 + %t186 = call ptr @fn_sconcat(ptr %t185, ptr @.str1433) + %t187 = call ptr @fn_sconcat(ptr @.str1432, ptr %t186) + %t188 = call ptr @fn_sconcat(ptr %t184, ptr %t187) + store ptr %t188, ptr %t178 + br label %ifend71 +ifend71: + %t189 = load ptr, ptr %t178 + %t190 = load ptr, ptr %t1 + %t191 = call ptr @fn_sconcat(ptr @.str1434, ptr %t190) + %t192 = call ptr @fn_sconcat(ptr %t189, ptr %t191) + store ptr %t192, ptr %t178 + %t193 = load ptr, ptr %t178 + %t194 = call i32 @system(ptr %t193) + store i32 %t194, ptr %t195 + %t196 = load i32, ptr %t5 + %t197 = icmp eq i32 %t196, 0 + %t198 = zext i1 %t197 to i32 + %t199 = icmp ne i32 %t198, 0 + br i1 %t199, label %then72, label %ifend74 +then72: + %t200 = load ptr, ptr %t159 + %t201 = call ptr @fn_sconcat(ptr @.str1435, ptr %t200) + %t202 = call i32 @system(ptr %t201) + br label %ifend74 +ifend74: + %t203 = load i32, ptr %t195 + %t204 = icmp ne i32 %t203, 0 + %t205 = zext i1 %t204 to i32 + %t206 = icmp ne i32 %t205, 0 + br i1 %t206, label %then75, label %ifend77 +then75: + call void @fn_die(ptr @.str1436) + br label %ifend77 +ifend77: + %t207 = load i32, ptr %t6 + %t208 = icmp ne i32 %t207, 0 + br i1 %t208, label %then78, label %ifend80 +then78: + %t209 = load ptr, ptr %t1 + %t210 = call i32 @system(ptr %t209) + store i32 %t210, ptr %t211 + %t212 = load i32, ptr %t211 + %t213 = lshr i32 %t212, 8 + %t214 = and i32 %t213, 255 + call void @exit(i32 %t214) + unreachable +ifend80: + br label %ret +ret: + %t215 = load i32, ptr %retval + ret i32 %t215 +} diff --git a/selfhost/main.ludic b/selfhost/main.ludic new file mode 100644 index 00000000..b0777322 --- /dev/null +++ b/selfhost/main.ludic @@ -0,0 +1,153 @@ +# main.ludic — the self-hosted Ludic front-end. +# +# ludicc lexes, parses, checks and lowers a .ludic file to LLVM IR, then drives +# clang (the IR assembler + system linker, the same role rustc/swiftc give it) +# to produce a native binary. No C is compiled: the emitted IR is Ludic's, and +# clang only assembles and links it. +# +# ludicc app.ludic -o bin/app # native binary (windowed if a game) +# ludicc app.ludic -o bin/app --headless # force headless +# ludicc app.ludic --emit-llvm -o app.ll # stop at the IR +# ludic app.ludic # compile to a temp binary and run it +# +# The multi-call twist: when argv[0] is "ludic" it defaults to compile-and-run. +# With no -o and no run, IR still goes to stdout — the contract build.sh and +# reseed.sh rely on, so the bootstrap is untouched. + +# basename: the part of a path after the last '/'. +fn base_name(path: ptr) -> ptr { + let last = 0 - 1 + let i = 0 + while peek8(path, i) != 0 { if peek8(path, i) == 47 { last = i } i = i + 1 } + return substr(path, last + 1, i - (last + 1)) +} + +# drop a trailing ".ludic" if present +fn strip_ludic(name: ptr) -> ptr { + let n = slen(name) + if n > 6 { + if streq(substr(name, n - 6, 6), ".ludic") { return substr(name, 0, n - 6) } + } + return name +} + +# env var with a fallback when unset +fn getenv_or(name: ptr, dflt: ptr) -> ptr { + let v = os_getenv(name) + if ptr_is_null(v) { return dflt } + return v +} + +# guarantee a directory string ends in '/' so path_join concatenates cleanly +fn ensure_slash(d: ptr) -> ptr { + let n = slen(d) + if n == 0 { return d } + if peek8(d, n - 1) == 47 { return d } + return sconcat(d, "/") +} + +fn die(msg: ptr) -> void { + file_write(file_stderr(), msg, slen(msg)) + os_exit(1) +} + +main { + let path = ptr_null() + let out = ptr_null() + let want = 0 # 0 = auto, 1 = windowed, 2 = headless + let emit_ir = false # --emit-llvm: stop after writing IR + let fmt = false # --fmt: lex + parse only, then exit (the doc-check gate) + let save = false # --save-temps: keep the intermediate .ll + let run = false # compile then execute the result + + # multi-call: invoked as `ludic` -> run mode by default + if streq(base_name(os_arg(0)), "ludic") { run = true } + + let ai = 1 + while ai < os_argc() { + let a = os_arg(ai) + if streq(a, "--windowed") { want = 1 } + else { if streq(a, "--headless") { want = 2 } + else { if streq(a, "--emit-llvm") { emit_ir = true } + else { if streq(a, "--fmt") { fmt = true } + else { if streq(a, "--save-temps") { save = true } + else { if streq(a, "--run") { run = true } + else { if streq(a, "-o") { ai = ai + 1 if ai < os_argc() { out = os_arg(ai) } } + else { + # an unknown flag is ignored (with a note) rather than mistaken for the + # input file — '-' is ASCII 45 + if peek8(a, 0) == 45 { + let m = sconcat("ludicc: ignoring unknown flag ", sconcat(a, "\n")) + file_write(file_stderr(), m, slen(m)) + } else { path = a } + } } } } } } } + ai = ai + 1 + } + + if ptr_is_null(path) { + die("usage: ludicc [-o out] [--windowed|--headless] [--emit-llvm] [--save-temps]\n") + } + let src = read_file(path) + if ptr_is_null(src) { die("ludicc: cannot open input\n") } + + cur_dir = dir_of(path) + lex(src) + parse_program() + + # --fmt is the doc-check gate: reaching here means it lexed and parsed. A parse + # error would already have exited nonzero, so a clean parse exits 0. (Canonical + # formatting output is not yet reimplemented on the self-hosted toolchain.) + if fmt { os_exit(0) } + + maybe_splice_runtime() + + # a game gets a window by default; a plain program stays headless. An explicit + # flag always wins. The stdout-IR path (no target) also stays headless, which + # is what reseed.sh compiles the compiler itself with. + let has_target = run or (not ptr_is_null(out)) + if want == 1 { g_windowed = true } + else { if want == 2 { g_windowed = false } + else { g_windowed = has_target and has_systems() } } + + emit_program() + + # --emit-llvm, or no binary target: emit IR and stop (stdout when out is null). + if emit_ir { ir_flush(out) return } + if not has_target { ir_flush(ptr_null()) return } + + # a run with no explicit -o lands in a temp file + if run and ptr_is_null(out) { + out = sconcat("/tmp/ludic-run-", strip_ludic(base_name(path))) + } + + # make the output directory if the user asked for e.g. bin/app + let odir = dir_of(out) + if slen(odir) > 0 { os_system(sconcat("mkdir -p ", odir)) } + + let ll = sconcat(out, ".ll") + if not ir_flush(ll) { die("ludicc: cannot write IR\n") } + + let cc = getenv_or("LUDIC_CC", "clang") + let home = ensure_slash(getenv_or("LUDIC_HOME", dir_of(os_arg(0)))) + + # clang twice: assemble the IR, then link. A windowed build adds the macOS + # platform layer and the Cocoa framework. + # -Wno-override-module: our IR carries an explicit target triple, which clang + # would otherwise warn about on every build. + let cmd = sconcat(cc, sconcat(" -O2 -Wno-override-module ", ll)) + if g_windowed { + let cocoa = path_join(home, "runtime/native/cocoa.ll") + cmd = sconcat(cmd, sconcat(" ", sconcat(cocoa, " -framework Cocoa -Wl,-rpath,@loader_path"))) + } + cmd = sconcat(cmd, sconcat(" -o ", out)) + + let rc = os_system(cmd) + if not save { os_system(sconcat("rm -f ", ll)) } + if rc != 0 { die("ludicc: link failed\n") } + + # run mode: execute the binary we just built and forward its exit code + if run { + let st = os_system(out) + os_exit(band(shr(st, 8), 255)) + } +} diff --git a/selfhost/parse.ludic b/selfhost/parse.ludic new file mode 100644 index 00000000..7bef78b4 --- /dev/null +++ b/selfhost/parse.ludic @@ -0,0 +1,322 @@ +# parse.ludic — recursive-descent parser: the token slice -> an AST. +# Reduced grammar: structs, vars, consts, fns, main; no ECS/scene/ui/match. +# Mirrors compiler/front/parse.c. Uses the global `toks` and a cursor `pi`. + +var pi: int = 0 +var prog: []Node # the top-level declarations +var g_game_name: ptr # the `game`/`module` name + +fn cur() -> Tok { return toks[pi] } +fn pk(o: int) -> Tok { return toks[pi + o] } +fn is_op(v: ptr) -> bool { let t = toks[pi] return t.kind == TK_OP and streq(t.text, v) } +fn is_id(v: ptr) -> bool { let t = toks[pi] return t.kind == TK_ID and streq(t.text, v) } +fn is_kw(v: ptr) -> bool { return is_id(v) } + +fn perr(msg: ptr) -> void { + let e = file_stderr() + file_write(e, "ludicc(self): parse error: ", 27) + file_write(e, msg, slen(msg)) + file_write(e, "\n", 1) + os_exit(1) +} + +fn eat_op(v: ptr) -> void { if not is_op(v) { perr(v) } pi = pi + 1 } +fn eat_id() -> ptr { + let t = toks[pi] + if t.kind != TK_ID { perr("expected identifier") } + pi = pi + 1 + return t.text +} +fn skipnl() -> void { while toks[pi].kind == TK_NL { pi = pi + 1 } } + +# a type: `[]T` slice, or a plain name (int/ptr/str/bool/struct) +fn ptype() -> ptr { + if is_op("[") { + pi = pi + 1 + eat_op("]") + let el = ptype() + let out = mem_alloc(slen(el) + 3) + poke8(out, 0, 91) poke8(out, 1, 93) # "[]" + let i = 0 + while peek8(el, i) != 0 { poke8(out, 2 + i, peek8(el, i)) i = i + 1 } + poke8(out, 2 + i, 0) + return out + } + return eat_id() +} + +# ---- expressions ----------------------------------------------------------- +fn expr() -> Node { return p_or() } + +fn args_call(call: Node) -> void { + eat_op("(") skipnl() + while not is_op(")") { push(call.kids, expr()) skipnl() if is_op(",") { pi = pi + 1 skipnl() } } + eat_op(")") +} + +fn p_primary() -> Node { + let t = toks[pi] + if t.kind == TK_INT { let n = node(E_INT) n.ival = t.ival pi = pi + 1 return n } + if t.kind == TK_FLOAT { let n = node(E_FLOAT) n.ival = t.ival pi = pi + 1 return n } + if t.kind == TK_STR { let n = node(E_STR) n.s = t.text pi = pi + 1 return n } + if t.kind == TK_ID { + if streq(t.text, "true") { let n = node(E_BOOL) n.ival = 1 pi = pi + 1 return n } + if streq(t.text, "false") { let n = node(E_BOOL) n.ival = 0 pi = pi + 1 return n } + if streq(t.text, "new") { pi = pi + 1 let n = node(E_NEW) n.s = ptype() return n } + let n = node(E_ID) n.s = t.text pi = pi + 1 return n + } + if is_op("(") { pi = pi + 1 skipnl() let e = expr() skipnl() eat_op(")") return e } + perr("expected expression") + return node(E_INT) +} + +fn p_postfix() -> Node { + let e = p_primary() + while true { + if is_op(".") { pi = pi + 1 let m = node(E_MEMBER) m.a = e m.s = eat_id() e = m } + else { if is_op("[") { pi = pi + 1 let ix = node(E_INDEX) ix.a = e ix.b = expr() eat_op("]") e = ix } + else { if is_op("(") { let c = node(E_CALL) c.a = e args_call(c) e = c } else { break } } } + } + return e +} + +fn p_unary() -> Node { + if is_op("-") { pi = pi + 1 let n = node(E_UN) n.s = "-" n.a = p_unary() return n } + if is_id("not") { pi = pi + 1 let n = node(E_UN) n.s = "not" n.a = p_unary() return n } + return p_postfix() +} + +fn mkbin(op: ptr, l: Node, r: Node) -> Node { let b = node(E_BIN) b.s = op b.a = l b.b = r return b } + +fn p_mul() -> Node { + let l = p_unary() + while is_op("*") or is_op("/") or is_op("%") { let op = toks[pi].text pi = pi + 1 l = mkbin(op, l, p_unary()) } + return l +} +fn p_add() -> Node { + let l = p_mul() + while is_op("+") or is_op("-") { let op = toks[pi].text pi = pi + 1 l = mkbin(op, l, p_mul()) } + return l +} +fn p_cmp() -> Node { + let l = p_add() + while is_op("<") or is_op("<=") or is_op(">") or is_op(">=") or is_op("==") or is_op("!=") { + let op = toks[pi].text pi = pi + 1 l = mkbin(op, l, p_add()) + } + return l +} +fn p_and() -> Node { + let l = p_cmp() + while is_id("and") { pi = pi + 1 l = mkbin("and", l, p_cmp()) } + return l +} +fn p_or() -> Node { + let l = p_and() + while is_id("or") { pi = pi + 1 l = mkbin("or", l, p_and()) } + return l +} + +# a record literal `{ field = value, ... }` — used by spawn component inits +fn record() -> Node { + eat_op("{") + let r = node(E_REC) + while true { skipnl() if is_op("}") { break } + let fi = node(E_FINIT) fi.s = eat_id() eat_op("=") fi.a = expr() push(r.kids, fi) + if is_op(",") { pi = pi + 1 } } + eat_op("}") return r +} + +# ---- statements ------------------------------------------------------------ +fn block() -> Node { + skipnl() eat_op("{") + let b = node(N_BLOCK) + while true { skipnl() if is_op("}") { break } push(b.kids, stmt()) } + eat_op("}") + return b +} + +fn stmt() -> Node { + let t = toks[pi] + if t.kind == TK_ID { + if streq(t.text, "let") { + pi = pi + 1 let n = node(S_LET) n.s = eat_id() + if is_op(":") { pi = pi + 1 n.ty = ptype() } + if is_op("=") { pi = pi + 1 n.a = expr() } + return n + } + if streq(t.text, "return") { + pi = pi + 1 let n = node(S_RETURN) + if toks[pi].kind != TK_NL and not is_op("}") { n.a = expr() } + return n + } + if streq(t.text, "if") { + pi = pi + 1 let n = node(S_IF) n.a = expr() n.b = block() skipnl() + if is_id("else") { pi = pi + 1 skipnl() + if is_id("if") { n.c = stmt() } else { n.c = block() } } + return n + } + if streq(t.text, "when") { # `when c { }` — an if with no else + pi = pi + 1 let n = node(S_IF) n.a = expr() n.b = block() + return n + } + if streq(t.text, "while") { pi = pi + 1 let n = node(S_WHILE) n.a = expr() n.b = block() return n } + if streq(t.text, "for") { + pi = pi + 1 + if is_op("(") { return parse_query_for() } + let n = node(S_FOR) n.s = eat_id() + let inkw = eat_id() # 'in' + n.a = expr() eat_op("..") n.b = expr() n.c = block() + return n + } + if streq(t.text, "spawn") { return parse_spawn() } + if streq(t.text, "machine") { + pi = pi + 1 let n = node(S_MACHINE) n.a = expr() skipnl() eat_op("{") + while true { skipnl() if is_op("}") { break } + let stkw = eat_id() # 'state' + let s = node(S_STATE) s.s = eat_id() eat_op("=") s.b = expr() skipnl() s.a = block() + push(n.kids, s) } + eat_op("}") return n + } + if streq(t.text, "become") { pi = pi + 1 let n = node(S_BECOME) n.s = eat_id() return n } + if streq(t.text, "enter") { pi = pi + 1 let n = node(S_BECOME) n.s = eat_id() n.ival = 1 return n } + if streq(t.text, "despawn") { pi = pi + 1 let n = node(S_DESPAWN) n.a = expr() return n } + if streq(t.text, "break") { pi = pi + 1 return node(S_BREAK) } + if streq(t.text, "continue") { pi = pi + 1 return node(S_CONTINUE) } + if streq(t.text, "match") { + pi = pi + 1 let n = node(S_MATCH) n.a = expr() skipnl() eat_op("{") + while true { + skipnl() if is_op("}") { break } + let arm = node(S_MARM) + while true { push(arm.kids, expr()) if is_op(",") { pi = pi + 1 skipnl() continue } break } + eat_op("=>") skipnl() + if is_op("{") { arm.a = block() } else { let b = node(N_BLOCK) push(b.kids, stmt()) arm.a = b } + push(n.kids, arm) + } + eat_op("}") return n + } + } + let e = expr() + if is_op("=") or is_op("+=") or is_op("-=") or is_op("*=") or is_op("/=") { + let n = node(S_ASSIGN) n.s = toks[pi].text pi = pi + 1 n.a = e n.b = expr() return n + } + let n = node(S_EXPR) n.a = e return n +} + +# ---- declarations ---------------------------------------------------------- +fn parse_struct() -> Node { + pi = pi + 1 let n = node(N_STRUCT) n.s = eat_id() skipnl() eat_op("{") + while true { skipnl() if is_op("}") { break } + let f = node(N_FIELD) f.s = eat_id() eat_op(":") f.ty = ptype() + if is_op("=") { pi = pi + 1 f.a = expr() } + push(n.kids, f) if is_op(",") { pi = pi + 1 } } + eat_op("}") return n +} +fn parse_var() -> Node { + pi = pi + 1 let n = node(N_VAR) n.s = eat_id() eat_op(":") n.ty = ptype() + if is_op("=") { pi = pi + 1 n.a = expr() } + return n +} +fn parse_const() -> Node { + pi = pi + 1 let n = node(N_CONST) n.s = eat_id() eat_op(":") n.ty = ptype() eat_op("=") n.a = expr() + return n +} +fn parse_fn() -> Node { + pi = pi + 1 let n = node(N_FN) n.s = eat_id() eat_op("(") + while not is_op(")") { + let p = node(N_PARAM) p.s = eat_id() eat_op(":") p.ty = ptype() push(n.kids, p) + if is_op(",") { pi = pi + 1 } + } + eat_op(")") + n.ty = "void" + if is_op("->") { pi = pi + 1 n.ty = ptype() } + n.a = block() + return n +} +fn parse_main() -> Node { pi = pi + 1 let n = node(N_MAIN) n.a = block() return n } + +# directory part of a path, including the trailing '/', or "" if none +fn dir_of(path: ptr) -> ptr { + let last = 0 - 1 + let i = 0 + while peek8(path, i) != 0 { if peek8(path, i) == 47 { last = i } i = i + 1 } + if last < 0 { return "" } + return substr(path, 0, last + 1) +} +fn path_join(dir: ptr, rel: ptr) -> ptr { + if peek8(rel, 0) == 47 { return rel } # absolute + return sconcat(dir, rel) +} + +var loaded_paths: []ptr +var cur_dir: ptr + +fn already_loaded(full: ptr) -> bool { + let i = 0 + while i < len(loaded_paths) { if streq(loaded_paths[i], full) { return true } i = i + 1 } + return false +} + +# parse one top-level declaration (or resolve an import) into `prog` +fn parse_one_decl() -> void { + if is_id("import") { pi = pi + 1 + let t = toks[pi] + if t.kind != TK_STR { perr("expected \"path\" after import") } + let rel = t.text pi = pi + 1 + do_import(rel) + return + } + if is_id("struct") { push(prog, parse_struct()) return } + if is_id("component") { push(prog, parse_component()) return } + if is_id("archetype") { push(prog, parse_archetype()) return } + if is_id("system") or is_id("edge") { push(prog, parse_system()) return } + if is_id("ui") { push(prog, parse_ui()) return } + if is_id("var") { push(prog, parse_var()) return } + if is_id("const") { push(prog, parse_const()) return } + if is_id("export") { pi = pi + 1 let f = parse_fn() f.ival = 1 push(prog, f) return } + if is_id("fn") or is_id("pure") { if is_id("pure") { pi = pi + 1 } push(prog, parse_fn()) return } + if is_id("extern") { push(prog, parse_extern()) return } + if is_id("main") { push(prog, parse_main()) return } + perr("expected declaration") +} + +# lex and parse an imported fragment into `prog`, saving/restoring lexer state +fn do_import(rel: ptr) -> void { + let full = path_join(cur_dir, rel) + if already_loaded(full) { return } + push(loaded_paths, full) + let src = read_file(full) + if ptr_is_null(src) { perr(sconcat("cannot open import ", full)) } + let saved_toks = toks let saved_pi = pi let saved_dir = cur_dir + cur_dir = dir_of(full) + lex(src) # resets the global token stream + pi = 0 + skipnl() + while toks[pi].kind != TK_EOF { parse_one_decl() skipnl() } + toks = saved_toks pi = saved_pi cur_dir = saved_dir +} + +# a game (has systems/components) links the Ludic runtime; auto-splice it the +# way the C compiler does. Tools (a `main` block, no ECS) get nothing. +fn maybe_splice_runtime() -> void { + if not has_ecs() { return } + let saved = cur_dir + cur_dir = "" + do_import("runtime/native/core.ludic") + cur_dir = saved +} + +fn parse_program() -> void { + prog = new []Node + loaded_paths = new []ptr + skipnl() + g_game_name = "Ludic" + # imports may precede the game block + while is_id("import") { pi = pi + 1 let t = toks[pi] let rel = t.text pi = pi + 1 do_import(rel) skipnl() } + if is_id("game") or is_id("module") { pi = pi + 1 g_game_name = eat_id() skipnl() eat_op("{") } + while true { + skipnl() + if toks[pi].kind == TK_EOF { break } + if is_op("}") { break } + parse_one_decl() + } +} diff --git a/selfhost/parse_game.ludic b/selfhost/parse_game.ludic new file mode 100644 index 00000000..13031389 --- /dev/null +++ b/selfhost/parse_game.ludic @@ -0,0 +1,144 @@ +# parse_game.ludic — the ECS front-end: component and system declarations, +# `for (vars) in query [terms] where cond`, spawn and despawn. Mirrors the +# game-construct parsing in compiler/front/parse.c. + +fn parse_component() -> Node { + pi = pi + 1 let n = node(N_COMP) n.s = eat_id() skipnl() eat_op("{") + while true { skipnl() if is_op("}") { break } + let f = node(N_FIELD) f.s = eat_id() eat_op(":") f.ty = ptype() + if is_op("=") { pi = pi + 1 f.a = expr() } + push(n.kids, f) if is_op(",") { pi = pi + 1 } } + eat_op("}") return n +} + +# skip an @annotation or a reads/writes/query/... clause we don't model yet +fn skip_clause() -> void { + if is_op("[") { let depth = 0 + while true { if is_op("[") { depth = depth + 1 } if is_op("]") { depth = depth - 1 } + pi = pi + 1 if depth == 0 { break } } + } +} + +fn parse_system() -> Node { + if is_id("edge") { pi = pi + 1 } # optional `edge` modifier before `system` + pi = pi + 1 let n = node(N_SYS) n.s = eat_id() n.ty = "Update" + # clauses: @anno, phase X, reads/writes/needs/uses [..], query (..) [..] + # A `query (vars) [terms] where c` clause desugars to a body wrapped in one + # `for (vars) in query [terms] where c { ... }` — the same S_QUERY node the + # inline form builds, so `qdecl.ludic` and the inline form share a lowering. + let has_q = false + let qn = node(S_QUERY) + while true { + skipnl() # clauses may span several lines + if is_op("@") { pi = pi + 1 let a = eat_id() if is_op("(") { let d = 0 # @anno, one per turn so a + while true { if is_op("(") { d = d + 1 } if is_op(")") { d = d - 1 } pi = pi + 1 if d == 0 { break } } } + continue } # newline-separated @anno re-skips at the loop top + if is_id("phase") { pi = pi + 1 n.ty = eat_id() continue } + if is_id("reads") or is_id("writes") or is_id("needs") or is_id("uses") { pi = pi + 1 skip_clause() continue } + if is_id("query") { + pi = pi + 1 has_q = true + if is_op("(") { eat_op("(") # optional (vars); omitted when nothing binds + while not is_op(")") { let v = node(E_ID) v.s = eat_id() push(qn.kids, v) if is_op(",") { pi = pi + 1 } } + eat_op(")") } + qn.c = parse_query_tail() + qn.b = qn.c.a # where-expr (or null) + continue + } + break + } + skipnl() + let body = block() + if has_q { + qn.a = body + let wrap = node(N_BLOCK) push(wrap.kids, qn) + n.a = wrap + } else { n.a = body } + return n +} + +# `[Term, ...]` with optional `where `, returning a node whose kids are +# the terms (E_ID with ival=1 for {Tag} filters) and .a the where-expr or null. +fn parse_query_tail() -> Node { + eat_op("[") + let q = node(N_BLOCK) + while not is_op("]") { + if is_op("{") { pi = pi + 1 let t = node(E_ID) t.s = eat_id() t.ival = 1 push(q.kids, t) eat_op("}") } + else { let t = node(E_ID) t.s = eat_id() t.ival = 0 push(q.kids, t) } + if is_op(",") { pi = pi + 1 } + } + eat_op("]") + if is_id("where") { pi = pi + 1 q.a = expr() } + return q +} + +# `for (a, b) in query [Pos, Vel] where ... { body }` +fn parse_query_for() -> Node { + let n = node(S_QUERY) + eat_op("(") + while not is_op(")") { let v = node(E_ID) v.s = eat_id() push(n.kids, v) if is_op(",") { pi = pi + 1 } } + eat_op(")") + let inkw = eat_id() # 'in' + let qkw = eat_id() # 'query' + n.c = parse_query_tail() + n.b = n.c.a # where + n.a = block() + return n +} + +fn parse_spawn() -> Node { + pi = pi + 1 let n = node(S_SPAWN) n.s = eat_id() skipnl() eat_op("{") + while true { + skipnl() if is_op("}") { break } + let ci = node(E_FINIT) ci.s = eat_id() eat_op("=") + ci.a = record() # { field = val, ... } + push(n.kids, ci) + if is_op(",") { pi = pi + 1 } + } + eat_op("}") return n +} + +# archetype Name { CompA, CompB } — a named entity kind (bundle of components) +fn parse_archetype() -> Node { + pi = pi + 1 let n = node(N_ARCH) n.s = eat_id() skipnl() eat_op("{") + while true { skipnl() if is_op("}") { break } + let c = node(E_ID) c.s = eat_id() push(n.kids, c) + if is_op(",") { pi = pi + 1 } skipnl() } + eat_op("}") return n +} + +# extern fn name(params) -> T = "symbol" +fn parse_extern() -> Node { + pi = pi + 1 # 'extern' + let fnkw = eat_id() # 'fn' + let n = node(N_EXTERN) n.s = eat_id() eat_op("(") + while not is_op(")") { let p = node(N_PARAM) p.s = eat_id() eat_op(":") p.ty = ptype() push(n.kids, p) + if is_op(",") { pi = pi + 1 } } + eat_op(")") + n.ty = "void" + if is_op("->") { pi = pi + 1 n.ty = ptype() } + eat_op("=") + let t = toks[pi] # "symbol" + n.a = node(E_STR) n.a.s = t.text pi = pi + 1 + return n +} + +# ui Name { widget-tree } — parsed into a widget node tree (emitted later) +fn parse_widget() -> Node { + let w = node(N_UI) w.s = eat_id() # widget type name + w.b = node(N_BLOCK) # b.kids = props (E_FINIT) + while toks[pi].kind == TK_ID and toks[pi + 1].kind == TK_OP and streq(toks[pi + 1].text, "=") { + let pr = node(E_FINIT) pr.s = eat_id() eat_op("=") pr.a = expr() push(w.b.kids, pr) + } + skipnl() + if is_op("{") { pi = pi + 1 + while true { skipnl() if is_op("}") { break } push(w.kids, parse_widget()) } + eat_op("}") } + return w +} +fn parse_ui() -> Node { + pi = pi + 1 let n = node(N_UI) n.s = eat_id() n.ival = 1 # ival=1 marks the top ui block + skipnl() eat_op("{") skipnl() + n.a = parse_widget() + skipnl() eat_op("}") + return n +} diff --git a/selfhost/reseed.sh b/selfhost/reseed.sh new file mode 100755 index 00000000..1466ef20 --- /dev/null +++ b/selfhost/reseed.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# reseed.sh — regenerate the checked-in IR seed after a deliberate change to the +# self-host compiler. Uses the CURRENT seed (C-free) to produce the new one, so +# the C compiler is not reintroduced; falls back to the C ludicc if no seed +# builds. Always verify with ./selfhost/bootstrap-cfree.sh afterwards. +set -eu +cd "$(dirname "$0")/.." +CC="${LUDIC_CC:-clang}" +B=build/cfree; mkdir -p "$B" +FRAGS="selfhost/str.ludic selfhost/buf.ludic selfhost/io.ludic selfhost/ast.ludic +selfhost/lex.ludic selfhost/parse.ludic selfhost/parse_game.ludic selfhost/emit_core.ludic selfhost/emit_head.ludic +selfhost/emit_addr.ludic selfhost/emit_intrin.ludic selfhost/emit_intrin2.ludic selfhost/emit_math.ludic selfhost/emit_new.ludic +selfhost/emit_expr.ludic selfhost/emit_stmt.ludic selfhost/emit_ecs.ludic selfhost/emit_query.ludic selfhost/emit_spawn.ludic selfhost/emit_game.ludic selfhost/emit_machine.ludic selfhost/emit_save.ludic selfhost/emit_ui.ludic selfhost/emit_decl.ludic selfhost/main.ludic" +{ echo "game SelfHost {"; for f in $FRAGS; do cat "$f"; echo; done; echo "}"; } > "$B/selfhost.ludic" +if $CC selfhost/ludicc.seed.ll -o "$B/sh_old" 2>/dev/null; then + # compile once with the old seed, then AGAIN with the freshly built one so the + # seed is a fixed point of the NEW compiler, not a one-step image of the old. + "$B/sh_old" "$B/selfhost.ludic" > "$B/step1.ll" + $CC "$B/step1.ll" -o "$B/sh_new" + "$B/sh_new" "$B/selfhost.ludic" > selfhost/ludicc.seed.ll +else + echo "seed does not build; reseeding from the C ludicc" + ./selfhost/build.sh build/ludicc "$B/sh_c" + "$B/sh_c" "$B/selfhost.ludic" > selfhost/ludicc.seed.ll +fi +echo "reseeded: $(wc -l < selfhost/ludicc.seed.ll | tr -d ' ') lines" diff --git a/selfhost/str.ludic b/selfhost/str.ludic new file mode 100644 index 00000000..86124bb8 --- /dev/null +++ b/selfhost/str.ludic @@ -0,0 +1,58 @@ +# str.ludic — the string handling a compiler lives on: comparison, copying, +# slicing out substrings, and integer<->text. All over raw NUL-terminated +# byte buffers reached with peek8/poke8. + +fn streq(a: ptr, b: ptr) -> bool { + let i = 0 + while true { + let ca = peek8(a, i) + let cb = peek8(b, i) + if ca != cb { return false } + if ca == 0 { return true } + i = i + 1 + } + return false +} + +fn slen(s: ptr) -> int { + let n = 0 + while peek8(s, n) != 0 { n = n + 1 } + return n +} + +# a fresh NUL-terminated copy of src[start .. start+n] +fn substr(src: ptr, start: int, n: int) -> ptr { + let b = mem_alloc(n + 1) + let i = 0 + while i < n { poke8(b, i, peek8(src, start + i)) i = i + 1 } + poke8(b, n, 0) + return b +} + +fn char_is_digit(c: int) -> bool { return c >= 48 and c <= 57 } +fn char_is_alpha(c: int) -> bool { + if c >= 65 and c <= 90 { return true } + if c >= 97 and c <= 122 { return true } + return c == 95 +} +fn char_is_alnum(c: int) -> bool { return char_is_alpha(c) or char_is_digit(c) } + +# integer -> fresh decimal string +fn itoa(v: int) -> ptr { + if v == 0 { let z = mem_alloc(2) poke8(z, 0, 48) poke8(z, 1, 0) return z } + let neg = false + let x = v + if x < 0 { neg = true x = 0 - x } + let tmp = mem_alloc(16) + let n = 0 + while x > 0 { poke8(tmp, n, 48 + x % 10) x = x / 10 n = n + 1 } + let total = n + if neg { total = total + 1 } + let out = mem_alloc(total + 1) + let k = 0 + if neg { poke8(out, 0, 45) k = 1 } + let i = 0 + while i < n { poke8(out, k + i, peek8(tmp, n - 1 - i)) i = i + 1 } + poke8(out, total, 0) + return out +} diff --git a/selfhost/test.sh b/selfhost/test.sh new file mode 100755 index 00000000..39d8faa6 --- /dev/null +++ b/selfhost/test.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# test.sh — the self-hosting suite: the compiler is correct (compiles diverse +# programs to working binaries) and self-reproducing (the bootstrap fixpoint). +set -u +cd "$(dirname "$0")/.." +CC="${LUDIC_CC:-clang}" +PASS=0; FAIL=0 +ok() { printf " \033[32mPASS\033[0m %s\n" "$1"; PASS=$((PASS+1)); } +bad() { printf " \033[31mFAIL\033[0m %s\n" "$1"; FAIL=$((FAIL+1)); } + +echo "== build the self-host compiler (via the C ludicc) ==" +[ -x build/ludicc ] || ./build.sh >/dev/null 2>&1 +./build.sh examples/snake.ludic --headless >/dev/null 2>&1 && [ -x build/ludicc ] && ok "compiler builds from the IR seed (no C)" || { bad "self-host build"; exit 1; } + +echo "== the self-host compiler is correct ==" +run_case() { # name expected + local n="$1" exp="$2" + ./build/ludicc "selfhost/tests/$n.ludic" > "/tmp/sh_$n.ll" 2>"/tmp/sh_$n.err" || { bad "$n: self-host errored: $(head -1 /tmp/sh_$n.err)"; return; } + $CC "/tmp/sh_$n.ll" -o "/tmp/sh_$n" 2>/dev/null || { bad "$n: IR did not assemble"; return; } + local got; got=$("/tmp/sh_$n" 2>/dev/null | tr '\n' ' ' | sed 's/ *$//') + [ "$got" = "$exp" ] && ok "$n ($got)" || bad "$n: got [$got] want [$exp]" +} +run_case structs "7 9 109 2 42" +run_case slices "0 20 361 777" +run_case control "55 4 15 1" +run_case match_bits "1 2 9 16 4 9999" +run_case fixed "2 3 0 6 1" + +echo "== the self-host compiler compiles real games (vs golden output) ==" +# The golden PPMs in selfhost/golden/ were produced by the original C compiler. +# The self-hosted compiler must reproduce them exactly. +game_case() { # name keys + local n="$1" keys="$2" + ./selfhost/game-build.sh build/ludicc "examples/$n.ludic" "/tmp/ludic_${n}_sh" >/tmp/gb.out 2>&1 || { bad "$n: build ($(tail -1 /tmp/gb.out))"; return; } + printf '%s' "$keys" | "/tmp/ludic_${n}_sh" >/dev/null 2>&1; cp out.ppm "/tmp/${n}_sh.ppm" + cmp -s "selfhost/golden/$n.ppm" "/tmp/${n}_sh.ppm" && ok "$n matches the golden render" || bad "$n: differs from golden" +} +game_case snake "ddssaawwddss" +game_case menu "ssss" +game_case chronorift "ddddwwwwaassK" + +echo "== the bootstrap fixpoint (seeded from the C compiler) ==" +./selfhost/bootstrap.sh >/tmp/boot.out 2>&1 +if grep -q "FIXPOINT" /tmp/boot.out; then ok "gen2.ll == gen3.ll (compiler reproduces itself)"; else bad "fixpoint not reached"; cat /tmp/boot.out; fi + +echo "== the C-free bootstrap (from the checked-in IR seed, no C compiler) ==" +./selfhost/bootstrap-cfree.sh >/tmp/cfree.out 2>&1 +if grep -q "no C compiler" /tmp/cfree.out; then ok "seed.ll rebuilds the compiler and is its own fixed point"; else bad "C-free bootstrap failed (seed stale? run ./selfhost/reseed.sh)"; cat /tmp/cfree.out; fi + +echo +printf "== %d passed, %d failed ==\n" "$PASS" "$FAIL" +[ "$FAIL" -eq 0 ] diff --git a/selfhost/tests/control.ludic b/selfhost/tests/control.ludic new file mode 100644 index 00000000..467ae44e --- /dev/null +++ b/selfhost/tests/control.ludic @@ -0,0 +1,13 @@ +game T { + fn fib(n: int) -> int { if n < 2 { return n } return fib(n-1) + fib(n-2) } + main { + print_int(fib(10)) # 55 + let s = 0 + for i in 0 .. 10 { if i == 5 { break } if i % 2 == 0 { continue } s = s + i } + print_int(s) # 1+3 = 4 + let i = 0 let t = 0 + while true { i = i + 1 if i > 5 { break } t = t + i } + print_int(t) # 15 + if false and (1/0 == 0) { print_int(999) } else { print_int(1) } # short-circuit: no div by zero + } +} diff --git a/selfhost/tests/fixed.ludic b/selfhost/tests/fixed.ludic new file mode 100644 index 00000000..c898c004 --- /dev/null +++ b/selfhost/tests/fixed.ludic @@ -0,0 +1,12 @@ +game T { + main { + let half = 0.5 + let a = 1.5 + print_int(flr(a + half)) # flr(2.0) = 2 + print_int(flr(a * 2.0)) # flr(3.0) = 3 + let third = 1.0 / 3.0 + print_int(flr(third * 3.0)) # ~flr(1.0) = 1 (may be 0 with rounding) + print_int(flr(fx(5) + a)) # flr(6.5) = 6 + if a > half { print_int(1) } else { print_int(0) } # 1 + } +} diff --git a/selfhost/tests/match_bits.ludic b/selfhost/tests/match_bits.ludic new file mode 100644 index 00000000..2cce18aa --- /dev/null +++ b/selfhost/tests/match_bits.ludic @@ -0,0 +1,16 @@ +game T { + fn classify(c: int) -> int { + match c { 65, 66 => { return 1 } 67 => { return 2 } _ => { return 9 } } + return 0 + } + main { + print_int(classify(65)) # 1 + print_int(classify(67)) # 2 + print_int(classify(90)) # 9 + print_int(shl(1, 4)) # 16 + print_int(band(bor(4, 1), 6)) # 4 + let p = mem_alloc(16) + poke32(p, 1, 9999) + print_int(peek32(p, 1)) # 9999 + } +} diff --git a/selfhost/tests/slices.ludic b/selfhost/tests/slices.ludic new file mode 100644 index 00000000..254fed24 --- /dev/null +++ b/selfhost/tests/slices.ludic @@ -0,0 +1,11 @@ +game T { + main { + let xs = new []int + print_int(len(xs)) # 0 + for i in 0 .. 20 { push(xs, i * i) } + print_int(len(xs)) # 20 + print_int(xs[19]) # 361 + xs[3] = 777 + print_int(xs[3]) # 777 + } +} diff --git a/selfhost/tests/structs.ludic b/selfhost/tests/structs.ludic new file mode 100644 index 00000000..1f68f380 --- /dev/null +++ b/selfhost/tests/structs.ludic @@ -0,0 +1,20 @@ +game T { + struct P { x: int = 0, y: int = 7, next: P } + fn bump(p: P) -> void { p.x = p.x + 100 } + main { + let a = new P + print_int(a.y) # 7 default + a.x = 5 + let b = a + b.x = 9 + print_int(a.x) # 9 (reference) + bump(a) + print_int(a.x) # 109 + let c = new P + c.x = 2 + a.next = c + print_int(a.next.x) # 2 chained + a.next.x = 42 + print_int(c.x) # 42 + } +} diff --git a/test.sh b/test.sh new file mode 100755 index 00000000..27dacd1c --- /dev/null +++ b/test.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# test.sh — the regression suite. The compiler is now written in Ludic +# (selfhost/) and built from a checked-in LLVM-IR seed with clang; there is no C +# compiler in the repo. This suite proves the compiler builds from the seed, +# compiles every example to the byte-exact golden render, self-hosts to a +# fixpoint, and rebuilds itself with no C compiler. +set -u +cd "$(dirname "$0")" +PASS=0; FAIL=0 +ok() { printf " \033[32mPASS\033[0m %s\n" "$1"; PASS=$((PASS+1)); } +bad() { printf " \033[31mFAIL\033[0m %s\n" "$1"; FAIL=$((FAIL+1)); } + +echo "== the compiler is written in Ludic, not C ==" +if [ -e compiler ] || ls compiler/*.c >/dev/null 2>&1; then bad "compiler/ C sources still present" +else ok "no C compiler in the repo (compiler/ removed; the compiler is selfhost/*.ludic)"; fi +CLEFT=$(find tools -name '*.c' 2>/dev/null | wc -l | tr -d ' ') +ok "the only C left is the editor tooling ($CLEFT files: ludic-fmt, ludic-lsp)" + +echo "== the compiler builds from the IR seed (no C compiler) ==" +rm -f build/ludicc +if ./build.sh examples/snake.ludic --headless >/dev/null 2>&1 && [ -x build/ludicc ]; then + ok "clang selfhost/ludicc.seed.ll -> build/ludicc" +else bad "compiler did not build from the seed"; fi + +echo "== every example compiles to its golden render ==" +gcase() { # name keys + local n="$1" keys="$2" + ./selfhost/game-build.sh build/ludicc "examples/$n.ludic" "/tmp/ludic_${n}_t" >/tmp/gc.out 2>&1 || { bad "$n: build ($(tail -1 /tmp/gc.out))"; return; } + printf '%s' "$keys" | "/tmp/ludic_${n}_t" >/dev/null 2>&1 + cmp -s "selfhost/golden/$n.ppm" out.ppm && ok "$n renders the golden frame" || bad "$n: render differs from golden" +} +gcase snake "ddssaawwddss" +gcase menu "ssss" +gcase chronorift "ddddwwwwaassK" + +echo "== self-hosting and the bootstrap fixpoints ==" +./selfhost/test.sh >/tmp/sh.out 2>&1 +if grep -q "gen2.ll == gen3.ll" /tmp/sh.out; then ok "the compiler reproduces itself (fixpoint)"; else bad "fixpoint"; fi +if grep -q "no C compiler" /tmp/sh.out; then ok "the compiler rebuilds itself from the seed, C-free"; else bad "C-free bootstrap"; fi +CORR=$(grep -c PASS /tmp/sh.out) +ok "self-host suite: $CORR checks passed (see ./selfhost/test.sh)" + +echo "== documented syntax stays compilable (guards against spec/compiler drift) ==" +# Compiles a feature example end-to-end (parse -> lower -> link). qdecl exercises +# the `query (vars) [terms] where ...` clause in a system SIGNATURE. +qsmoke() { # name + local n="$1" + if ./selfhost/game-build.sh build/ludicc "examples/$n.ludic" "/tmp/ludic_${n}_s" >/tmp/qs.out 2>&1; then + ok "$n compiles (signature-query desugars to S_QUERY)" + else bad "$n: $(tail -1 /tmp/qs.out)"; fi +} +qsmoke qdecl +# --- Toolchain-agent CLI smoke tests append below this line --- +echo "== self-hosted front-end binaries (ludicc / ludic) ==" +# The two commands are one multi-call native binary built from the seed with +# clang alone. ludicc compiles; ludic compiles-and-runs. Each drives clang via +# the os_system intrinsic — no shell wrapper in between. +if ./build-cli.sh >/tmp/cli.out 2>&1 && [ -x ./ludicc ] && [ -x ./ludic ]; then + ok "build-cli.sh builds ./ludicc and ./ludic from the seed (clang-only)" +else bad "build-cli.sh: $(tail -1 /tmp/cli.out)"; fi + +# ludicc -o drives clang to a native binary; a game links windowed by default. +if ./ludicc examples/snake.ludic -o /tmp/cli_snake >/tmp/cli.out 2>&1 \ + && file /tmp/cli_snake 2>/dev/null | grep -q "Mach-O"; then + ok "ludicc app.ludic -o bin -> native executable" +else bad "ludicc -o: $(tail -1 /tmp/cli.out)"; fi + +# --emit-llvm stops at the IR. +if ./ludicc examples/snake.ludic --emit-llvm -o /tmp/cli_snake.ll >/tmp/cli.out 2>&1 \ + && head -1 /tmp/cli_snake.ll | grep -q "LLVM IR"; then + ok "ludicc --emit-llvm -> LLVM IR" +else bad "ludicc --emit-llvm: $(tail -1 /tmp/cli.out)"; fi + +# ludic compiles, runs, and forwards the program's exit code. +printf 'main { os_exit(42) }\n' > /tmp/cli_exit.ludic +./ludic /tmp/cli_exit.ludic >/tmp/cli.out 2>&1 +if [ "$?" -eq 42 ]; then ok "ludic app.ludic -> compiles, runs, forwards exit code" +else bad "ludic run: expected exit 42, got $? ($(tail -1 /tmp/cli.out))"; fi + +echo +printf "== %d passed, %d failed ==\n" "$PASS" "$FAIL" +[ "$FAIL" -eq 0 ] diff --git a/tools/atlas.ludic b/tools/atlas.ludic new file mode 100644 index 00000000..906743fd --- /dev/null +++ b/tools/atlas.ludic @@ -0,0 +1,56 @@ +# ============================================================================ +# atlas.ludic — render a Kenney tile pack as one index-labeled sheet, so you can +# see which sprite id is which before referring to it in a game. +# +# ludicc tools/atlas.ludic --headless -o build/atlas +# ./build/atlas && sips -s format png out.ppm --out atlas.png +# +# Replaces the old tools/atlas.c, which used the C runtime that no longer +# exists. It is the same program, in the language it is a tool for. +# ============================================================================ +game Atlas { + const DIR: str = "assets/kenney/tiny-dungeon/Tiles" + const N: int = 132 + const COLS: int = 12 + const CELL: int = 24 + + system Sheet phase Start { + clear(0x101018) + for i in 0 .. N { + let col = i % COLS + let row = i / COLS + let x = col * CELL + let y = row * CELL + # tile_0000.png … tile_0131.png — the id is the file's number + let id = load_png(tile_path(i)) + if id >= 0 { + draw_sprite(id, x + 4, y + 2) + } + text_int(x + 1, y + 18, i, 0x8090b0, 1) + } + present() + quit() + } + + # build "/tile_%04d.png" without a formatter: the runtime's string + # helpers write into a scratch buffer we own + fn tile_path(i: int) -> str { + let buf = atlas_buf() + let n = rt_put_str(buf, 0, DIR) + n = rt_put_str(buf, n, "/tile_") + if i < 1000 { poke8(buf, n, 48) n = n + 1 } + if i < 100 { poke8(buf, n, 48) n = n + 1 } + if i < 10 { poke8(buf, n, 48) n = n + 1 } + n = rt_put_int(buf, n, i) + n = rt_put_str(buf, n, ".png") + poke8(buf, n, 0) + return buf + } + + var atlas_scratch: ptr = ptr_null() + + fn atlas_buf() -> ptr { + if ptr_is_null(atlas_scratch) { atlas_scratch = mem_alloc(512) } + return atlas_scratch + } +} diff --git a/tools/build-tools.sh b/tools/build-tools.sh new file mode 100755 index 00000000..6c09a9f0 --- /dev/null +++ b/tools/build-tools.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# build-tools.sh — build the Ludic editor toolchain. +# +# ./tools/build-tools.sh -> build/ludic-fmt, build/ludic-lsp +# ./tools/build-tools.sh --test build, then run tools/test-tools.sh +# ./tools/build-tools.sh --install also symlink both into ~/.local/bin +# +# Both binaries are plain C with no dependencies, same as the compiler. They +# share the lexer and vocabulary in tools/ludic-tools/ludic_syntax.h, so a +# keyword added there reaches every editor at once. +set -e +cd "$(dirname "$0")/.." + +CC="${LUDIC_CC:-clang}" +CFLAGS="-O2 -Wall -Wno-unused-function" +SRC=tools/ludic-tools +OUT=build + +mkdir -p "$OUT" + +build_one() { + local name="$1" main="$2" + local newest + # rebuild when any header or the entry point is newer than the binary + if [ -x "$OUT/$name" ]; then + newest=$(find "$SRC" -name '*.h' -o -name "$(basename "$main")" | while read -r f; do + [ "$f" -nt "$OUT/$name" ] && echo new + done) + [ -z "$newest" ] && { echo "$name: up to date"; return; } + fi + echo "cc: $main -> $OUT/$name" + $CC $CFLAGS "$main" -o "$OUT/$name" +} + +build_one ludic-fmt "$SRC/ludic_fmt_main.c" +build_one ludic-lsp "$SRC/ludic_lsp.c" + +# The language server shells out to the compiler for real diagnostics, so having +# it around is most of the value. +if [ ! -x "$OUT/ludicc" ]; then + echo "note: $OUT/ludicc not built yet — run ./build.sh for compiler diagnostics" +fi + +# VS Code needs the grammar inside its own extension directory, so it gets a +# copy. A copy that can drift is the whole failure mode this toolchain is built +# to avoid, so it is refreshed here rather than maintained by hand, and +# test-tools.sh asserts the two are identical. +SHARED=tools/editors/shared +VSC=tools/editors/vscode +if [ -d "$VSC" ]; then + mkdir -p "$VSC/syntaxes" + for f in ludic.tmLanguage.json ludic.markdown-injection.json; do + cmp -s "$SHARED/$f" "$VSC/syntaxes/$f" || { cp "$SHARED/$f" "$VSC/syntaxes/$f"; echo "sync: $f -> $VSC/syntaxes/"; } + done + cmp -s "$SHARED/language-configuration.json" "$VSC/language-configuration.json" || { + cp "$SHARED/language-configuration.json" "$VSC/language-configuration.json" + echo "sync: language-configuration.json -> $VSC/" + } +fi + +if [ "$1" = "--install" ] || [ "$2" = "--install" ]; then + mkdir -p "$HOME/.local/bin" + ln -sf "$PWD/$OUT/ludic-fmt" "$HOME/.local/bin/ludic-fmt" + ln -sf "$PWD/$OUT/ludic-lsp" "$HOME/.local/bin/ludic-lsp" + echo "linked into ~/.local/bin (make sure it is on your PATH)" +fi + +if [ "$1" = "--test" ] || [ "$2" = "--test" ]; then + exec ./tools/test-tools.sh +fi + +echo "done. editors: see tools/editors/README.md" diff --git a/tools/check-docs.py b/tools/check-docs.py new file mode 100755 index 00000000..7981b07d --- /dev/null +++ b/tools/check-docs.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""check-docs.py — every ```ludic fence in the docs is checked against the +compiler, so documentation cannot drift away from the language. + +A fence declares its own intent with an in-fence comment (`#` is a Ludic +comment, so the marker is valid code and visible to a reader): + + # doc-check: skip illustrative or pseudo-syntax; not checked + # doc-check: expect-error must FAIL to compile (error demonstrations) + +Anything else must PARSE. The gate is `ludicc --fmt`, not a full build: it runs +lex + parse, which is what catches syntax drift, but does not resolve +identifiers — so an excerpt may reference components and registers that live in +the surrounding program it was lifted from, and still be checked. + +A bare fragment is wrapped first: a declaration list goes inside +`game DocCheck { ... }`, loose statements inside a Start system. +""" +import re, subprocess, sys, os, tempfile + +LC = './build/ludicc' +DECL = ('game','module','component','archetype','system','edge','fn','pure', + 'extern','const','var','ui','scene','import') + +def classify(body): + first = next((l.strip() for l in body.split('\n') + if l.strip() and not l.strip().startswith('#')), '') + head = first.split('(')[0].split()[0] if first else '' + if head in ('game','module'): return 'whole' + return 'decls' if head in DECL else 'stmts' + +def wraps(body, kind): + """Candidate framings, best guess first. An excerpt often mixes declarations + with loose statements, so both are tried and either parsing counts.""" + if kind == 'whole': return [body] + as_decls = 'game DocCheck {\n' + body + '\n}\n' + as_stmts = 'game DocCheck {\n system DocS phase Start {\n' + body + '\n }\n}\n' + return [as_decls, as_stmts] if kind == 'decls' else [as_stmts, as_decls] + +def fences(path): + t = open(path).read() + for m in re.finditer(r'^```ludic\n(.*?)^```', t, re.S | re.M): + yield t[:m.start()].count('\n') + 1, m.group(1) + +def main(argv): + report = '--report' in argv + docs = [p for p in argv if p.endswith('.md')] + ok = bad = skipped = 0 + failures = [] + for path in docs: + for line, body in fences(path): + if '# doc-check: skip' in body: + skipped += 1; continue + expect_error = '# doc-check: expect-error' in body + kind = classify(body) + parsed, first_err = False, None + for src in wraps(body, kind): + with tempfile.NamedTemporaryFile('w', suffix='.ludic', delete=False) as f: + f.write(src); tmp = f.name + # bytes, not text: a diagnostic may echo a partial multibyte char + r = subprocess.run([LC, tmp, '--fmt'], capture_output=True) + os.unlink(tmp) + if r.returncode == 0: parsed = True; break + # keep the best-guess framing's error; later ones are fallbacks + if first_err is None: first_err = r.stderr + if parsed != (not expect_error): + bad += 1 + want = 'be rejected' if expect_error else 'parse' + err = (first_err or b'').decode('utf-8','replace').strip().split('\n')[0] + failures.append(f"{path}:{line} expected to {want}: {err[:90]}") + else: + ok += 1 + print(f" doc fences: {ok} as documented, {bad} drifted, {skipped} skipped") + for f in failures: print(f" {f}") + if report: return 0 + return 1 if bad else 0 + +sys.exit(main(sys.argv[1:])) diff --git a/tools/check-vocabulary.py b/tools/check-vocabulary.py new file mode 100755 index 00000000..15c452e9 --- /dev/null +++ b/tools/check-vocabulary.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""Guard against the failure mode this whole layout exists to prevent. + +The Ludic vocabulary — keywords, types, phases, builtins, intrinsics — is +written down in five places that cannot include each other: + + compiler/**/*.c BUILTINS[] the language itself + compiler/**/*.c INTRINSICS[] the language itself + tools/ludic-tools/ ludic_syntax.h the toolchain's source of truth + tools/editors/shared/ the TextMate grammar (JSON, no includes) + tools/editors/jetbrains/ LudicVocabulary (Kotlin, no includes) + +Adding a builtin to the compiler and forgetting the rest is silent: the editor +just stops colouring it, and nobody notices for months. So it is checked. +""" +import json +import os +import re +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +problems = [] + + +def read(*parts): + with open(os.path.join(ROOT, *parts)) as fh: + return fh.read() + + +def c_string_list(text, name): + """Names in `static const char* NAME[] = { "a", "b", 0 };`""" + m = re.search(r"\b" + name + r"\s*\[\s*\]\s*=\s*\{(.*?)\}\s*;", text, re.S) + if not m: + problems.append(f"{name}: not found") + return set() + return set(re.findall(r'"([^"]+)"', m.group(1))) + + +def c_table_names(text, name): + """First string of each row in a `{ "name", ... }` table.""" + m = re.search(r"\b" + name + r"\s*\[\s*\]\s*=\s*\{(.*?)\n\s*\}\s*;", text, re.S) + if not m: + problems.append(f"{name}: not found") + return set() + return set(re.findall(r'\{\s*"([^"]+)"', m.group(1))) + + +def kotlin_set(text, name): + """Names in `val NAME = setOf(...)`, found by matching the parentheses — + a non-greedy regex silently runs past a one-line setOf into the next one.""" + m = re.search(r"\bval\s+" + name + r"\s*=\s*setOf\(", text) + if not m: + problems.append(f"Kotlin {name}: not found") + return set() + i = m.end() + depth = 1 + while i < len(text) and depth: + if text[i] == "(": + depth += 1 + elif text[i] == ")": + depth -= 1 + i += 1 + body = re.sub(r"//[^\n]*", "", text[m.end():i - 1]) + return set(re.findall(r'"([^"]+)"', body)) + + +def grammar_alternation(grammar, path, marker): + """Names in a `\\b(a|b|c)\\b` match inside the TextMate grammar.""" + node = grammar + for key in path: + node = node[key] + for pat in node: + rx = pat.get("match", "") + if marker in rx: + inner = re.search(r"\\b\((.*?)\)\\b", rx) + if inner: + return set(inner.group(1).split("|")) + problems.append(f"grammar: no rule containing {marker!r}") + return set() + + +def compare(label, reference, other, other_label, ignore=frozenset()): + missing = (reference - other) - ignore + extra = (other - reference) - ignore + if missing: + problems.append(f"{other_label} is missing {label}: {', '.join(sorted(missing))}") + if extra: + problems.append(f"{other_label} has unknown {label}: {', '.join(sorted(extra))}") + + +syntax_h = read("tools", "ludic-tools", "ludic_syntax.h") +def read_table_owner(table): + """Find whichever compiler translation unit declares a table. + + The compiler is split by concern and files move; hardcoding a path here + turns a routine refactor into a spurious vocabulary failure. + """ + import glob + for path in sorted(glob.glob(os.path.join(ROOT, "compiler", "**", "*.c"), recursive=True)): + text = open(path, encoding="utf-8").read() + if re.search(r"\b%s\s*\[\s*\]" % re.escape(table), text): + return text + return None # the compiler is now written in Ludic (selfhost/); no C table + +ludicc_c = read_table_owner("BUILTINS") +native_c = read_table_owner("INTRINSICS") +kotlin = read("tools", "editors", "jetbrains", "src", "main", "kotlin", "io", "ludic", "ide", "LudicTokens.kt") +grammar = json.loads(read("tools", "editors", "shared", "ludic.tmLanguage.json")) + +# --- the toolchain header is the reference --------------------------------- +h_decl = c_string_list(syntax_h, "LUDIC_KW_DECL") +h_clause = c_string_list(syntax_h, "LUDIC_KW_CLAUSE") +h_stmt = c_string_list(syntax_h, "LUDIC_KW_STMT") +h_types = c_string_list(syntax_h, "LUDIC_TYPES") +h_phases = c_string_list(syntax_h, "LUDIC_PHASES") +h_widgets = c_string_list(syntax_h, "LUDIC_WIDGETS") +h_builtins = c_table_names(syntax_h, "LUDIC_BUILTINS") +h_intrinsics = c_table_names(syntax_h, "LUDIC_INTRINSICS") + +# --- against the compiler's builtin/intrinsic tables, when a C compiler is +# present. The compiler is now written in Ludic (selfhost/), so this +# cross-check is skipped; the editor tools remain checked against each other. +if ludicc_c is not None: + compare("builtins", c_table_names(ludicc_c, "BUILTINS"), h_builtins, "ludic_syntax.h") +if native_c is not None: + compare("intrinsics", c_table_names(native_c, "INTRINSICS"), h_intrinsics, "ludic_syntax.h") + +# --- against the JetBrains lexer ------------------------------------------- +compare("declaration keywords", h_decl, kotlin_set(kotlin, "DECL"), "LudicTokens.kt") +compare("clause keywords", h_clause, kotlin_set(kotlin, "CLAUSE"), "LudicTokens.kt") +compare("statement keywords", h_stmt, kotlin_set(kotlin, "STMT"), "LudicTokens.kt") +compare("primitive types", h_types, kotlin_set(kotlin, "PRIMITIVES"), "LudicTokens.kt") +compare("phases", h_phases, kotlin_set(kotlin, "PHASES"), "LudicTokens.kt") +compare("widgets", h_widgets, kotlin_set(kotlin, "WIDGETS"), "LudicTokens.kt") +compare("builtins", h_builtins | h_intrinsics, kotlin_set(kotlin, "BUILTINS"), "LudicTokens.kt") + +# --- against the TextMate grammar ------------------------------------------ +gpath = ["repository", "builtin", "patterns"] +compare("builtins", h_builtins, grammar_alternation(grammar, gpath, "rng_chance"), "ludic.tmLanguage.json") +compare("intrinsics", h_intrinsics, grammar_alternation(grammar, gpath, "mem_alloc"), "ludic.tmLanguage.json") +kpath = ["repository", "keyword", "patterns"] +compare("phases", h_phases, grammar_alternation(grammar, kpath, "FixedUpdate"), "ludic.tmLanguage.json") +compare("primitive types", h_types, grammar_alternation(grammar, kpath, "fixed"), "ludic.tmLanguage.json") + +if problems: + print("vocabulary drift:", file=sys.stderr) + for p in problems: + print(" -", p, file=sys.stderr) + sys.exit(1) +sys.exit(0) diff --git a/tools/editors/README.md b/tools/editors/README.md new file mode 100644 index 00000000..a60f6875 --- /dev/null +++ b/tools/editors/README.md @@ -0,0 +1,148 @@ +# Ludic in your editor + +Everything here is built on one idea: **write the language knowledge once, in C, +and let every editor talk to it.** There is one lexer, one vocabulary, one +formatter and one language server. VS Code and JetBrains get first-class plugins +because those are the two that were asked for; every other editor gets the same +capabilities by pointing at the same binary. + +``` +tools/ludic-tools/ the actual language knowledge, in C, no dependencies + ludic_syntax.h lexer + the vocabulary — the source of truth + ludic_fmt.h comment-preserving formatter + ludic_index.h error-tolerant reader: declarations, bindings, scopes + ludic_workspace.h multi-file model: imports, compilation units, Markdown + ludic_json.h just enough JSON for LSP + ludic_fmt_main.c -> build/ludic-fmt + ludic_lsp.c -> build/ludic-lsp + +tools/editors/ + shared/ TextMate grammar + Markdown injection + language config + vscode/ VS Code extension + jetbrains/ IntelliJ Platform plugin (Community editions included) + neovim/ helix/ emacs/ sublime/ zed/ configuration, no plugin needed +``` + +## Build it + +```bash +./tools/build-tools.sh +``` + +Produces `build/ludic-fmt` and `build/ludic-lsp`. Add `--install` to symlink both +into `~/.local/bin`, `--test` to run `tools/test-tools.sh` afterwards. + +## What you get, in any editor + +| Feature | How | +|---|---| +| Syntax highlighting | LSP semantic tokens, or the TextMate grammar with no server at all | +| Diagnostics | structural errors as you type; `ludicc`'s own errors on save | +| Completion | context-aware — see below | +| Hover | signature + docs for builtins, intrinsics, and everything you declared | +| Go to definition, find usages, rename | across the whole compilation unit, following `import` — by resolving each occurrence, not by matching text, so renaming a component's `x` leaves every other `x` alone | +| Formatting | whole-file, comment-preserving, idempotent | +| Outline, folding, inlay hints, signature help, document links | | +| ` ```ludic ` in Markdown | highlighted, checked and formatted | + +Completion knows where the caret is: fields after `.`, components inside +`query [...]` and after `spawn`, phase names after `phase`, scene names after +`enter`, widget types and props inside a `ui` block, types after `:` and `->`, +and otherwise keywords, builtins, and everything in scope. + +## Per-editor setup + +- **VS Code** — [`vscode/`](vscode/). `npm install && npx @vscode/vsce package`, then + install the `.vsix`. Finds the binaries under `build/` on its own. +- **JetBrains** — [`jetbrains/`](jetbrains/). `./gradlew buildPlugin`, then install the + zip from disk. Uses LSP4IJ rather than the paid-IDE LSP API, so it works in + Community editions too. +- **Neovim** — `require('ludic').setup()` from [`neovim/`](neovim/lua/ludic.lua). +- **Helix** — merge [`helix/languages.toml`](helix/languages.toml) into your config. +- **Emacs** — [`emacs/ludic-mode.el`](emacs/ludic-mode.el); eglot is wired up in one line. +- **Sublime** — [`sublime/README.md`](sublime/README.md); the TextMate grammar loads as-is. +- **Zed** — [`zed/README.md`](zed/README.md); LSP-only, no grammar to build. +- **Anything else** that speaks LSP: + + ``` + command: build/ludic-lsp --stdio + languages: ludic, markdown + initializationOptions: { "compilerPath": "build/ludicc", "compilerDiagnostics": true, "indentSize": 2 } + ``` + +## Markdown + +Markdown fenced-code highlighting is not one standard — it is three mechanisms, +and this ships all three so that a ` ```ludic ` block works wherever you write +prose: + +1. **TextMate injection** (`shared/ludic.markdown-injection.json`) — what VS Code, + Sublime and other TextMate-based editors use. It is a plain grammar file with + an `injectionSelector`, so it is portable rather than VS Code-specific. +2. **Language-ID resolution** — JetBrains' Markdown support matches a fence's + info string against registered language IDs, so the plugin registering as + `Ludic` is all that is needed; no Markdown-specific code exists in the plugin. +3. **The language server** — `ludic-lsp` accepts Markdown documents directly. It + copies the buffer, blanks every byte outside a ` ```ludic ` fence, and + analyses the result; offsets still line up with the real file, so semantic + highlighting, hover, completion and go-to-definition all work inside fences + with no editor-side support at all. This is the fallback that works even + where the other two do not. + + It reports **no diagnostics** in Markdown, deliberately. A fence is a + snippet — an elision mark, or a body shown without its enclosing `game` + block — so nearly every error found there would be the documentation doing + its job. `ludic-fmt --check` still keeps the fences formatted, which is the + part of "is this doc correct" that can be answered without guessing. + +The formatter handles Markdown too, which keeps documentation honest: + +```bash +build/ludic-fmt --check LANGUAGE.md README.md # CI: fail if a fence is unformatted +build/ludic-fmt -w LANGUAGE.md # reformat the fences, leave the prose +``` + +## Keeping a tree formatted + +```bash +ln -sf ../../tools/git-hooks/pre-commit .git/hooks/pre-commit +``` + +The hook runs `ludic-fmt --check` over the staged `.ludic` and `.md` files only, +and does nothing at all when `build/ludic-fmt` has not been built — so it never +blocks a commit on a machine that has not run `build-tools.sh`. + +## Why the formatter is not `ludicc --fmt` + +The compiler has a canonical printer, and it is the right tool for seeing what +the compiler parsed. It is the wrong tool for an editor: it walks the AST *after* +import splicing, so it drops every comment and inlines every imported file into +whichever file you pointed it at. Running it as format-on-save on +`chronorift/combat.ludic` would replace that file with the whole game. + +`ludic-fmt` works on the token stream instead. Nothing is dropped or reordered — +every token is re-emitted in order, and the only freedom taken is the whitespace +between them. Lines are re-indented and respaced but never joined or split, so +you keep control of line structure. + +Two carve-outs keep the output idiomatic rather than merely uniform, because +both spellings are what the language documents and uses: + +- runs of two or more spaces are preserved, so hand-aligned columns + (`const R_DIR: int = 0 # 0 up`) survive a save; +- `id=Root` inside a `ui` block and `{Enemy}` inside a query stay tight. + +`tools/test-tools.sh` checks the property that matters: formatting every file in +the tree and re-running the *compiler's* canonical dump produces byte-identical +output. The formatter cannot change what a program means. + +## Keeping it honest + +The vocabulary is written down in five places that cannot include each other — +the compiler's two tables, `ludic_syntax.h`, the TextMate grammar (JSON), and the +JetBrains lexer (Kotlin). Adding a builtin and forgetting the rest is silent +failure, so `tools/check-vocabulary.py` compares all five and +`tools/test-tools.sh` runs it. + +When you add a keyword or builtin: put it in `ludic_syntax.h`, then run +`./tools/test-tools.sh` and let it tell you which copies still need it. diff --git a/tools/editors/emacs/ludic-mode.el b/tools/editors/emacs/ludic-mode.el new file mode 100644 index 00000000..fa9b8b94 --- /dev/null +++ b/tools/editors/emacs/ludic-mode.el @@ -0,0 +1,70 @@ +;;; ludic-mode.el --- Major mode for the Ludic game language -*- lexical-binding: t; -*- + +;; Highlighting here is a deliberate minimum: enough for a file to be readable +;; with nothing installed. Everything real -- completion, diagnostics, hover, +;; formatting -- comes from ludic-lsp via eglot (built into Emacs 29) or lsp-mode. +;; +;; Usage: +;; (add-to-list 'load-path "/path/to/gpp/tools/editors/emacs") +;; (require 'ludic-mode) + +;;; Code: + +(defconst ludic--declaration-keywords + '("game" "module" "import" "component" "archetype" "ui" "scene" "layer" + "const" "var" "export" "fn" "pure" "extern" "system" "edge" "start" "on")) + +(defconst ludic--clause-keywords + '("phase" "query" "reads" "writes" "needs" "uses" + "requires" "ensures" "invariant" "effects")) + +(defconst ludic--statement-keywords + '("let" "return" "if" "else" "when" "while" "for" "in" "spawn" "despawn" + "match" "machine" "state" "become" "enter" "where" "and" "or")) + +(defconst ludic--types '("int" "fixed" "bool" "entity" "str" "ptr" "void")) +(defconst ludic--phases '("Start" "Input" "FixedUpdate" "Update" "LateUpdate" "Render")) + +(defconst ludic-font-lock-keywords + (list + (cons (regexp-opt ludic--declaration-keywords 'symbols) 'font-lock-keyword-face) + (cons (regexp-opt ludic--clause-keywords 'symbols) 'font-lock-preprocessor-face) + (cons (regexp-opt ludic--statement-keywords 'symbols) 'font-lock-keyword-face) + (cons (regexp-opt ludic--types 'symbols) 'font-lock-type-face) + (cons (regexp-opt ludic--phases 'symbols) 'font-lock-builtin-face) + (cons "\\_<\\(true\\|false\\)\\_>" 'font-lock-constant-face) + (cons "@[A-Za-z_][A-Za-z0-9_]*" 'font-lock-preprocessor-face) + ;; components, archetypes, scenes and UI handles are Capitalised by convention + (cons "\\_<[A-Z][A-Za-z0-9_]*\\_>" 'font-lock-type-face) + (cons "\\_<\\([a-z_][A-Za-z0-9_]*\\)\\s-*(" '(1 font-lock-function-name-face)))) + +(defvar ludic-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?# "<" table) + (modify-syntax-entry ?\n ">" table) + (modify-syntax-entry ?_ "_" table) + (modify-syntax-entry ?\" "\"" table) + table) + "Syntax table for `ludic-mode'.") + +;;;###autoload +(define-derived-mode ludic-mode prog-mode "Ludic" + "Major mode for editing Ludic source." + :syntax-table ludic-mode-syntax-table + (setq-local font-lock-defaults '(ludic-font-lock-keywords)) + (setq-local comment-start "# ") + (setq-local comment-end "") + (setq-local indent-tabs-mode nil) + (setq-local tab-width 2) + (setq-local standard-indent 2)) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.ludic\\'" . ludic-mode)) + +;; eglot: one line, and the server does the rest. Markdown is registered too so +;; that ```ludic fences are analysed in prose files. +(with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs '(ludic-mode . ("ludic-lsp" "--stdio")))) + +(provide 'ludic-mode) +;;; ludic-mode.el ends here diff --git a/tools/editors/helix/languages.toml b/tools/editors/helix/languages.toml new file mode 100644 index 00000000..47c8ea1e --- /dev/null +++ b/tools/editors/helix/languages.toml @@ -0,0 +1,24 @@ +# Ludic for Helix. Append to ~/.config/helix/languages.toml, adjusting the two +# paths. Highlighting comes from the server's semantic tokens; Helix applies +# them with no grammar to build. + +[[language]] +name = "ludic" +scope = "source.ludic" +file-types = ["ludic"] +comment-token = "#" +indent = { tab-width = 2, unit = " " } +language-servers = ["ludic-lsp"] +auto-format = true +roots = ["build.sh", "LANGUAGE.md", ".git"] + +[language-server.ludic-lsp] +command = "ludic-lsp" +args = ["--stdio"] + +# Ludic fences inside Markdown: point Helix's markdown at the same server so +# `# ```ludic` blocks get diagnostics too. Merge this with your existing +# markdown entry rather than adding a second one. +# [[language]] +# name = "markdown" +# language-servers = ["marksman", "ludic-lsp"] diff --git a/tools/editors/jetbrains/README.md b/tools/editors/jetbrains/README.md new file mode 100644 index 00000000..1b124d3b --- /dev/null +++ b/tools/editors/jetbrains/README.md @@ -0,0 +1,58 @@ +# Ludic for JetBrains IDEs + +Works in IntelliJ IDEA (Community and Ultimate), CLion, GoLand, PyCharm, Rider, +WebStorm — anything on the IntelliJ Platform 2023.2 through 2026.2 +(`since-build` 232, `until-build` 262.*). + +`until-build` 262 is deliberately ahead of the newest released platform — 2025.3 +is build **253**, and no 262 IDE exists yet. That headroom is the point: an +`until-build` pinned to today's IDE gets the plugin auto-disabled the moment a +user upgrades. + +Two things are machine-checked rather than assumed, because a plugin that +packages cleanly can still fail to load: + +- `./gradlew verifyPlugin` runs JetBrains' own Plugin Verifier over the built + artifact against 2025.3 and reports **Compatible**, with no deprecated or + scheduled-for-removal API usages. +- `./gradlew runIde` boots a real IDEA 2025.3 with the plugin installed. The + sandbox log line to look for is + `Loaded custom plugins: LSP4IJ (0.20.1), Ludic (1.0.0)` in + `.intellijPlatform/sandbox/Ludic/IC-2025.3/log/idea.log`. + +**If the plugin does not appear in Settings -> Plugins after installing**, the +cause is almost always that the IDE's build number is outside +`since-build`..`until-build`. IntelliJ installs the declared dependency (LSP4IJ) +from Marketplace first and only then rejects the incompatible plugin, so the +symptom is "LSP4IJ got installed, mine did not". Check **Help -> About** for the +build number and widen `pluginUntilBuild` in `gradle.properties` to match. + +## Building + +Gradle must run on **JDK 17–21**. A newer JDK fails with a bare version number +as the error message, which is not obvious the first time you see it: + +```bash +export JAVA_HOME=$(/usr/libexec/java_home -v 21) # macOS +cd tools/editors/jetbrains +./gradlew buildPlugin # -> build/distributions/Ludic-1.0.0.zip +./gradlew runIde # try it in a sandbox IDE +``` + +The first build downloads an IntelliJ IDEA Community distribution (over 1 GB), +so expect it to take a while; later builds take seconds. Once the cache is warm, + +```bash +LUDIC_TEST_JETBRAINS=1 ./tools/test-tools.sh +``` + +includes the plugin build in the toolchain's own test run. + +Install the zip with **Settings -> Plugins -> ⚙ -> Install Plugin from Disk**. +LSP4IJ is a required dependency; the IDE offers to install it for you. + +## Settings + +**Settings -> Languages & Frameworks -> Ludic** — the path to `ludic-lsp` and to +`ludicc`. Both default to `build/` under the project root, which is where +`tools/build-tools.sh` puts them. diff --git a/tools/editors/jetbrains/build.gradle.kts b/tools/editors/jetbrains/build.gradle.kts new file mode 100644 index 00000000..ded193a0 --- /dev/null +++ b/tools/editors/jetbrains/build.gradle.kts @@ -0,0 +1,96 @@ +import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType + +plugins { + id("java") + id("org.jetbrains.kotlin.jvm") version "2.4.10" + // The IntelliJ Platform Gradle Plugin 2.x. The 1.x line (org.jetbrains.intellij) + // is superseded and does not run on current Gradle. + id("org.jetbrains.intellij.platform") version "2.18.1" +} + +group = providers.gradleProperty("pluginGroup").get() +version = providers.gradleProperty("pluginVersion").get() + +repositories { + mavenCentral() + intellijPlatform { + defaultRepositories() + } +} + +dependencies { + testImplementation("junit:junit:4.13.2") + intellijPlatform { + // Community, deliberately: the plugin must work in the free IDEs, which + // is also why the language server is wired up through LSP4IJ rather + // than com.intellij.platform.lsp (Ultimate and friends only). + // useInstaller = false takes the Maven artifact (com.jetbrains.intellij.idea:ideaIC) + // instead of the .dmg/.tar.gz installer. Since 2025.x the Community installer is + // published as `idea-`, not `ideaIC-`, and the installer path + // cannot find it; the Maven coordinate is unaffected by that rename. + intellijIdeaCommunity(providers.gradleProperty("platformVersion").get()) { + useInstaller = false + } + bundledPlugin("org.intellij.plugins.markdown") + plugin("com.redhat.devtools.lsp4ij", providers.gradleProperty("lsp4ijVersion").get()) + // JetBrains' Plugin Verifier CLI, used by the verifyPlugin task below + pluginVerifier() + // headless fixtures for the platform tests in src/test + testFramework(TestFrameworkType.Platform) + } +} + +kotlin { + jvmToolchain(17) +} + +intellijPlatform { + pluginConfiguration { + name = providers.gradleProperty("pluginName") + version = providers.gradleProperty("pluginVersion") + ideaVersion { + sinceBuild = providers.gradleProperty("pluginSinceBuild") + untilBuild = providers.gradleProperty("pluginUntilBuild") + } + } + // Compatibility is claimed up to pluginUntilBuild, so it gets checked + // against that IDE rather than assumed: `./gradlew verifyPlugin` runs + // JetBrains' own Plugin Verifier over the built artifact. + pluginVerification { + ides { + // The platform this is compiled against, which is also the newest + // that exists (2025.3 = build 253). until-build claims 262, which + // no released IDE reaches yet. + create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("platformVersion").get()) { + useInstaller = false + } + } + } + + buildSearchableOptions = false + + // The platform's bytecode instrumenter only adds @NotNull assertions and + // compiles .form files. This plugin is Kotlin with no GUI forms, so it has + // nothing to instrument — and skipping it avoids the instrumenter's JBR + // probing, which fails on a plain JDK layout. + instrumentCode = false +} + +// `./gradlew runIde` opens the Ludic repository itself, so the sandbox has real +// .ludic files to look at and build/ludic-lsp sitting where the plugin expects. +// Three levels up: jetbrains -> editors -> tools -> repository root. Getting +// this wrong points the IDE at tools/, where no build/ludic-lsp exists, and the +// language server then cannot find itself. +val repoRoot: File = rootProject.projectDir.parentFile.parentFile.parentFile +tasks.named("runIde") { + args = listOf(repoRoot.absolutePath) +} + +tasks.test { + useJUnit() + testLogging { + events("passed", "failed", "skipped") + showStandardStreams = false + } +} diff --git a/tools/editors/jetbrains/gradle.properties b/tools/editors/jetbrains/gradle.properties new file mode 100644 index 00000000..42ab63ca --- /dev/null +++ b/tools/editors/jetbrains/gradle.properties @@ -0,0 +1,26 @@ +pluginGroup = io.ludic.ide +pluginName = Ludic +pluginVersion = 1.0.0 + +# 2023.2 is the first build with the platform APIs this plugin uses. LSP4IJ (not +# the paid-IDE LSP API) supplies the language-server bridge, so Community +# editions are supported as well as Ultimate. +pluginSinceBuild = 232 +# Deliberately ahead of the newest released platform (2025.3 is build 253): an +# until-build that stops at today's IDE gets the plugin auto-disabled the moment +# a user upgrades. 262 buys roughly three release cycles of headroom. The APIs +# this plugin uses are the stable ones (LexerBase, SyntaxHighlighter, +# ParserDefinition, FoldingBuilder), and everything project-wide is delegated to +# ludic-lsp over a versioned protocol rather than to platform internals. +pluginUntilBuild = 262.* + +platformVersion = 2025.3 +lsp4ijVersion = 0.20.1 + +# Gradle itself must run on JDK 17-21; a newer JDK reports only its version +# number as the failure. The Kotlin toolchain below is pinned separately. +# The wrapper is Gradle 9.x because IntelliJ Platform Gradle Plugin 2.13+ +# requires it. +org.gradle.jvmargs = -Xmx2g +org.gradle.caching = true +kotlin.stdlib.default.dependency = false diff --git a/tools/editors/jetbrains/gradle/wrapper/gradle-wrapper.jar b/tools/editors/jetbrains/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..8bdaf60c Binary files /dev/null and b/tools/editors/jetbrains/gradle/wrapper/gradle-wrapper.jar differ diff --git a/tools/editors/jetbrains/gradle/wrapper/gradle-wrapper.properties b/tools/editors/jetbrains/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..c42672d9 --- /dev/null +++ b/tools/editors/jetbrains/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/tools/editors/jetbrains/gradlew b/tools/editors/jetbrains/gradlew new file mode 100755 index 00000000..adff685a --- /dev/null +++ b/tools/editors/jetbrains/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/tools/editors/jetbrains/gradlew.bat b/tools/editors/jetbrains/gradlew.bat new file mode 100644 index 00000000..e509b2dd --- /dev/null +++ b/tools/editors/jetbrains/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/tools/editors/jetbrains/settings.gradle.kts b/tools/editors/jetbrains/settings.gradle.kts new file mode 100644 index 00000000..8138fbf6 --- /dev/null +++ b/tools/editors/jetbrains/settings.gradle.kts @@ -0,0 +1,2 @@ +// The distribution is named after this, so it is the plugin name, not a slug. +rootProject.name = "Ludic" diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicConfigurable.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicConfigurable.kt new file mode 100644 index 00000000..6632ad0c --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicConfigurable.kt @@ -0,0 +1,83 @@ +package io.ludic.ide + +import com.intellij.openapi.options.Configurable +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.TextFieldWithBrowseButton +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.components.JBLabel +import com.intellij.util.ui.FormBuilder +import javax.swing.JComponent +import javax.swing.JPanel +import javax.swing.JSpinner +import javax.swing.SpinnerNumberModel + +/** Settings -> Languages and Frameworks -> Ludic */ +class LudicConfigurable(private val project: Project) : Configurable { + private val serverField = TextFieldWithBrowseButton() + private val compilerField = TextFieldWithBrowseButton() + private val diagnostics = JBCheckBox("Report compiler errors on save") + private val indent = JSpinner(SpinnerNumberModel(2, 1, 8, 1)) + private var panel: JPanel? = null + + override fun getDisplayName() = "Ludic" + + override fun createComponent(): JComponent { + // The title travels on the descriptor now; the four-argument overload + // that took it separately is scheduled for removal. + serverField.addBrowseFolderListener( + project, + FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor().withTitle("Path to ludic-lsp") + ) + compilerField.addBrowseFolderListener( + project, + FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor().withTitle("Path to ludicc") + ) + + panel = FormBuilder.createFormBuilder() + .addLabeledComponent(JBLabel("Language server (ludic-lsp):"), serverField, 1, false) + .addComponentToRightColumn( + JBLabel("Leave empty to use build/ludic-lsp under the project, then PATH.") + ) + .addLabeledComponent(JBLabel("Compiler (ludicc):"), compilerField, 1, false) + .addComponentToRightColumn( + JBLabel("Used for authoritative diagnostics. Empty means build/ludicc.") + ) + .addComponent(diagnostics) + .addLabeledComponent(JBLabel("Formatter indent:"), indent, 1, false) + .addComponentFillVertically(JPanel(), 0) + .panel + reset() + return panel!! + } + + private fun settings() = LudicSettings.of(project) + + override fun isModified(): Boolean { + val s = settings() + return serverField.text != s.serverPath || + compilerField.text != s.compilerPath || + diagnostics.isSelected != s.compilerDiagnostics || + (indent.value as Int) != s.indentSize + } + + override fun apply() { + val s = settings() + s.serverPath = serverField.text.trim() + s.compilerPath = compilerField.text.trim() + s.compilerDiagnostics = diagnostics.isSelected + s.indentSize = indent.value as Int + } + + override fun reset() { + val s = settings() + serverField.text = s.serverPath + compilerField.text = s.compilerPath + diagnostics.isSelected = s.compilerDiagnostics + indent.value = s.indentSize + } + + override fun disposeUIResources() { + panel = null + } +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicEditorSupport.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicEditorSupport.kt new file mode 100644 index 00000000..97195476 --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicEditorSupport.kt @@ -0,0 +1,85 @@ +package io.ludic.ide + +import com.intellij.lang.BracePair +import com.intellij.lang.Commenter +import com.intellij.lang.PairedBraceMatcher +import com.intellij.lang.folding.FoldingBuilderEx +import com.intellij.lang.folding.FoldingDescriptor +import com.intellij.openapi.editor.Document +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IElementType + +/** + * The small editor mechanics the platform expects a language to provide: how to + * comment a line, which delimiters pair up, and what can be folded. None of + * this needs the language server, so none of it waits for one. + */ +class LudicCommenter : Commenter { + override fun getLineCommentPrefix() = "# " + override fun getBlockCommentPrefix(): String? = null + override fun getBlockCommentSuffix(): String? = null + override fun getCommentedBlockCommentPrefix(): String? = null + override fun getCommentedBlockCommentSuffix(): String? = null +} + +class LudicBraceMatcher : PairedBraceMatcher { + override fun getPairs(): Array = PAIRS + + override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, next: IElementType?): Boolean = true + + override fun getCodeConstructStart(file: PsiFile?, openingBraceOffset: Int): Int = openingBraceOffset + + private companion object { + // Structural braces only: a record literal shares the token type, so + // marking them all structural would make the "matched brace" gutter + // noisy inside `spawn Hero { Pos = { x = 1 } }`. + val PAIRS = arrayOf( + BracePair(LudicTokens.BRACE, LudicTokens.BRACE, true), + BracePair(LudicTokens.BRACKET, LudicTokens.BRACKET, false), + BracePair(LudicTokens.PAREN, LudicTokens.PAREN, false) + ) + } +} + +/** + * Folds every braced block. Working off the lexer's token stream rather than a + * PSI tree keeps this correct for a flat PSI, and it degrades gracefully on a + * file with unbalanced braces, which is most files while they are being typed. + */ +class LudicFoldingBuilder : FoldingBuilderEx(), DumbAware { + override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array { + val text = root.containingFile?.text ?: return emptyArray() + val lexer = LudicLexer() + lexer.start(text, 0, text.length, 0) + + val opens = ArrayDeque() + val regions = mutableListOf() + val node = root.node ?: return emptyArray() + + while (lexer.tokenType != null) { + if (lexer.tokenType == LudicTokens.BRACE) { + when (text[lexer.tokenStart]) { + '{' -> opens.addLast(lexer.tokenStart) + '}' -> { + val open = opens.removeLastOrNull() + if (open != null) { + val end = lexer.tokenEnd + // only worth folding when it actually spans lines + if (document.getLineNumber(end) > document.getLineNumber(open)) { + regions += FoldingDescriptor(node, TextRange(open, end)) + } + } + } + } + } + lexer.advance() + } + return regions.toTypedArray() + } + + override fun getPlaceholderText(node: com.intellij.lang.ASTNode) = "{...}" + override fun isCollapsedByDefault(node: com.intellij.lang.ASTNode) = false +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicLanguage.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicLanguage.kt new file mode 100644 index 00000000..80332909 --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicLanguage.kt @@ -0,0 +1,32 @@ +package io.ludic.ide + +import com.intellij.lang.Language +import com.intellij.openapi.fileTypes.LanguageFileType +import com.intellij.openapi.util.IconLoader +import com.intellij.openapi.vfs.VirtualFile +import javax.swing.Icon + +/** + * The language ID matters more than it looks: the IDE's Markdown support + * resolves a fenced block's info string ("```ludic") against registered + * language IDs, so registering as "Ludic" is what makes fences in .md files + * highlight, with no Markdown-specific code on our side. + */ +object LudicLanguage : Language("Ludic") { + private fun readResolve(): Any = LudicLanguage + override fun getDisplayName() = "Ludic" + override fun isCaseSensitive() = true +} + +object LudicIcons { + val FILE: Icon = IconLoader.getIcon("/icons/ludic.svg", LudicIcons::class.java) +} + +object LudicFileType : LanguageFileType(LudicLanguage) { + private fun readResolve(): Any = LudicFileType + override fun getName() = "Ludic" + override fun getDescription() = "Ludic source" + override fun getDefaultExtension() = "ludic" + override fun getIcon(): Icon = LudicIcons.FILE + override fun getCharset(file: VirtualFile, content: ByteArray): String = "UTF-8" +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicLexer.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicLexer.kt new file mode 100644 index 00000000..1b18b173 --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicLexer.kt @@ -0,0 +1,148 @@ +package io.ludic.ide + +import com.intellij.lexer.LexerBase +import com.intellij.psi.TokenType +import com.intellij.psi.tree.IElementType + +/** + * A hand-written lexer matching tools/ludic-tools/ludic_syntax.h token for + * token. Hand-written rather than generated because the grammar is small, the + * rules are the ones the C lexer already implements, and keeping the two + * readable side by side is worth more here than a JFlex spec. + * + * It must never throw and never fail to advance: the IDE lexes half-typed text + * constantly, so anything unrecognised becomes one BAD character and the scan + * carries on. + */ +class LudicLexer : LexerBase() { + private var buffer: CharSequence = "" + private var startOffset = 0 + private var endOffset = 0 + private var tokenStart = 0 + private var tokenEnd = 0 + private var tokenType: IElementType? = null + + override fun start(buffer: CharSequence, startOffset: Int, endOffset: Int, initialState: Int) { + this.buffer = buffer + this.startOffset = startOffset + this.endOffset = endOffset + this.tokenStart = startOffset + this.tokenEnd = startOffset + advance() + } + + override fun getState() = 0 + override fun getTokenType(): IElementType? = tokenType + override fun getTokenStart() = tokenStart + override fun getTokenEnd() = tokenEnd + override fun getBufferSequence() = buffer + override fun getBufferEnd() = endOffset + + private fun at(i: Int): Char = if (i in startOffset until endOffset) buffer[i] else ' ' + private fun isIdStart(c: Char) = c.isLetter() || c == '_' + private fun isIdPart(c: Char) = c.isLetterOrDigit() || c == '_' + private fun isSpace(c: Char) = c == ' ' || c == '\t' || c == '\r' || c == '\n' + + override fun advance() { + tokenStart = tokenEnd + if (tokenStart >= endOffset) { + tokenType = null + return + } + + var i = tokenStart + val c = at(i) + + if (isSpace(c)) { + while (i < endOffset && isSpace(at(i))) i++ + emit(i, TokenType.WHITE_SPACE) + return + } + if (c == '#') { + while (i < endOffset && at(i) != '\n') i++ + emit(i, LudicTokens.COMMENT) + return + } + if (c == '"') { + i++ + while (i < endOffset && at(i) != '"' && at(i) != '\n') { + if (at(i) == '\\' && i + 1 < endOffset) i += 2 else i++ + } + if (i < endOffset && at(i) == '"') i++ + emit(i, LudicTokens.STRING) + return + } + if (c == '\'') { + i++ + if (at(i) == '\\' && i + 1 < endOffset) i += 2 else if (i < endOffset && at(i) != '\n') i++ + if (i < endOffset && at(i) == '\'') i++ + emit(i, LudicTokens.CHAR) + return + } + if (c.isDigit()) { + if (c == '0' && (at(i + 1) == 'x' || at(i + 1) == 'X')) { + i += 2 + while (i < endOffset && (at(i).isDigit() || at(i) in 'a'..'f' || at(i) in 'A'..'F')) i++ + } else { + while (i < endOffset && at(i).isDigit()) i++ + if (at(i) == '.' && at(i + 1).isDigit()) { + i++ + while (i < endOffset && at(i).isDigit()) i++ + } + } + emit(i, LudicTokens.NUMBER) + return + } + // @deterministic is one token: the sigil never stands alone + if (c == '@' && isIdStart(at(i + 1))) { + i++ + while (i < endOffset && isIdPart(at(i))) i++ + emit(i, LudicTokens.ANNOTATION) + return + } + if (isIdStart(c)) { + while (i < endOffset && isIdPart(at(i))) i++ + val word = buffer.subSequence(tokenStart, i).toString() + val type = when { + word == "true" || word == "false" -> LudicTokens.BOOLEAN + word in LudicVocabulary.PRIMITIVES -> LudicTokens.PRIMITIVE + word in LudicVocabulary.PHASES -> LudicTokens.PHASE + word in LudicVocabulary.DECL -> LudicTokens.DECL_KEYWORD + word in LudicVocabulary.CLAUSE -> LudicTokens.CLAUSE + word in LudicVocabulary.STMT -> LudicTokens.KEYWORD + word in LudicVocabulary.BUILTINS -> LudicTokens.BUILTIN + word[0].isUpperCase() -> LudicTokens.TYPE_NAME + else -> LudicTokens.IDENTIFIER + } + emit(i, type) + return + } + // two-character operators before one-character ones + val two = if (i + 1 < endOffset) buffer.subSequence(i, i + 2).toString() else "" + if (two in TWO_CHAR_OPS) { + emit(i + 2, LudicTokens.OPERATOR) + return + } + when (c) { + '{', '}' -> { emit(i + 1, LudicTokens.BRACE); return } + '[', ']' -> { emit(i + 1, LudicTokens.BRACKET); return } + '(', ')' -> { emit(i + 1, LudicTokens.PAREN); return } + ',' -> { emit(i + 1, LudicTokens.COMMA); return } + } + if (c in SINGLE_CHAR_OPS) { + emit(i + 1, LudicTokens.OPERATOR) + return + } + emit(i + 1, LudicTokens.BAD) + } + + private fun emit(end: Int, type: IElementType) { + tokenEnd = end + tokenType = type + } + + private companion object { + val TWO_CHAR_OPS = setOf("->", "+=", "-=", "*=", "/=", "==", "!=", "<=", ">=", "&&", "||", "..", "=>") + const val SINGLE_CHAR_OPS = "+-*/%<>=:.!@;" + } +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicParserDefinition.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicParserDefinition.kt new file mode 100644 index 00000000..4b1d6cd9 --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicParserDefinition.kt @@ -0,0 +1,52 @@ +package io.ludic.ide + +import com.intellij.lang.ASTNode +import com.intellij.lang.ParserDefinition +import com.intellij.lang.PsiParser +import com.intellij.lexer.Lexer +import com.intellij.openapi.project.Project +import com.intellij.psi.FileViewProvider +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.TokenType +import com.intellij.psi.tree.IFileElementType +import com.intellij.psi.tree.TokenSet +import com.intellij.extapi.psi.ASTWrapperPsiElement +import com.intellij.extapi.psi.PsiFileBase + +/** + * A flat PSI: every token becomes a leaf under the file node, with no tree + * structure above it. + * + * That is enough for the two things the platform genuinely needs a parser for — + * injecting Ludic into Markdown fences, and letting the editor treat a .ludic + * file as a real language rather than plain text — while all actual analysis + * stays in ludic-lsp, where it is shared with every other editor. Building a + * second, divergent parser in Kotlin would mean two grammars to keep honest + * against one compiler. + */ +class LudicParserDefinition : ParserDefinition { + override fun createLexer(project: Project?): Lexer = LudicLexer() + + override fun createParser(project: Project?): PsiParser = PsiParser { root, builder -> + val mark = builder.mark() + while (!builder.eof()) builder.advanceLexer() + mark.done(root) + builder.treeBuilt + } + + override fun getFileNodeType(): IFileElementType = LudicTokens.FILE + override fun getCommentTokens(): TokenSet = TokenSet.create(LudicTokens.COMMENT) + override fun getStringLiteralElements(): TokenSet = TokenSet.create(LudicTokens.STRING, LudicTokens.CHAR) + override fun getWhitespaceTokens(): TokenSet = TokenSet.create(TokenType.WHITE_SPACE) + // Only ever reached for composite nodes, and this grammar marks none beyond + // the file itself — but the platform requires an answer, so give it a real + // PSI element rather than something that would surprise it later. + override fun createElement(node: ASTNode): PsiElement = ASTWrapperPsiElement(node) + override fun createFile(viewProvider: FileViewProvider): PsiFile = LudicPsiFile(viewProvider) +} + +class LudicPsiFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, LudicLanguage) { + override fun getFileType() = LudicFileType + override fun toString() = "Ludic file" +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicServer.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicServer.kt new file mode 100644 index 00000000..4551ad0f --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicServer.kt @@ -0,0 +1,158 @@ +package io.ludic.ide + +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.xmlb.XmlSerializerUtil +import com.redhat.devtools.lsp4ij.LanguageServerFactory +import com.redhat.devtools.lsp4ij.client.LanguageClientImpl +import com.redhat.devtools.lsp4ij.server.CannotStartProcessException +import com.redhat.devtools.lsp4ij.server.ProcessStreamConnectionProvider +import com.redhat.devtools.lsp4ij.server.StreamConnectionProvider +import java.io.File + +/** + * Where to find the toolchain. Both paths may be left blank, in which case the + * plugin looks under the project root for what tools/build-tools.sh produces — + * which is the case for anyone working in the Ludic repository itself. + */ +@Service(Service.Level.PROJECT) +@State(name = "LudicSettings", storages = [Storage("ludic.xml")]) +class LudicSettings : PersistentStateComponent { + var serverPath: String = "" + var compilerPath: String = "" + var compilerDiagnostics: Boolean = true + var indentSize: Int = 2 + + override fun getState(): LudicSettings = this + override fun loadState(state: LudicSettings) = XmlSerializerUtil.copyBean(state, this) + + companion object { + fun of(project: Project): LudicSettings = project.service() + } +} + +/** + * First existing executable among the usual places, or null. + * + * Takes the project root as a plain path rather than a Project so it can be + * tested without booting an IDE — this lookup silently returning null is the + * difference between a working language server and one that never starts. + */ +internal fun findExecutable(root: String?, configured: String, names: List, subdirs: List): String? { + if (configured.isNotBlank()) { + val f = File(expandHome(configured)) + return if (f.canExecute()) f.absolutePath else null + } + if (root == null) return searchPath(names) + for (dir in subdirs) { + for (name in names) { + val f = File(File(root, dir), name) + if (f.isFile && f.canExecute()) return f.absolutePath + } + } + return searchPath(names) +} + +/** Fall back to PATH, so a system-wide install works with no configuration. */ +private fun searchPath(names: List): String? { + val path = System.getenv("PATH") ?: return null + for (dir in path.split(File.pathSeparator)) { + for (name in names) { + val f = File(dir, name) + if (f.isFile && f.canExecute()) return f.absolutePath + } + } + return null +} + +private fun expandHome(p: String) = + if (p.startsWith("~")) System.getProperty("user.home") + p.substring(1) else p + +class LudicConnectionProvider(private val project: Project) : ProcessStreamConnectionProvider() { + + /** + * Resolve at start(), not at construction. + * + * The provider is built when the project opens, which is usually before the + * toolchain has been compiled. Resolving in an `init` block froze that + * answer forever: build ludic-lsp afterwards and the server stayed dead + * until the IDE was restarted, with `commands=[]` as the only clue. + */ + override fun start() { + val settings = LudicSettings.of(project) + val root = project.basePath + setCommands(serverCommand(root, settings.serverPath) + ?: throw CannotStartProcessException(notFoundMessage(root, settings.serverPath))) + root?.let { setWorkingDirectory(it) } + super.start() + } + + /** + * What went wrong, in terms of the user's filesystem. "commands=[]" tells + * nobody anything; this names every path that was tried. + */ + private fun notFoundMessage(root: String?, configured: String): String = buildString { + if (configured.isNotBlank()) { + append("The Ludic language server configured at '") + append(configured) + append("' is missing or not executable.") + } else { + append("Could not find the 'ludic-lsp' executable. Looked in:\n") + SERVER_SUBDIRS.forEach { d -> + append(" ") + append(if (root != null) File(File(root, d), "ludic-lsp").path else "/$d/ludic-lsp") + append('\n') + } + append(" and on PATH.\n") + } + append("\nBuild it with ./tools/build-tools.sh from the repository root, ") + append("or set the path in Settings | Languages & Frameworks | Ludic. ") + append("Syntax highlighting works without it; completion and diagnostics do not.") + } + + /** + * Passed to the server's `initialize`. The server can find `ludicc` on its + * own, but telling it explicitly means the IDE's setting wins. + */ + override fun getInitializationOptions(rootUri: VirtualFile?): Any { + val settings = LudicSettings.of(project) + val compiler = findExecutable( + project.basePath, settings.compilerPath, + listOf("ludicc", "ludicc.exe"), + COMPILER_SUBDIRS + ) ?: "" + return mapOf( + "compilerPath" to compiler, + "compilerDiagnostics" to settings.compilerDiagnostics, + "indentSize" to settings.indentSize + ) + } +} + +/** + * The exact argv the language server is launched with, or null when the binary + * cannot be found. Split out from start() so the command line itself is + * testable — an empty or wrong command here is invisible until LSP4IJ reports + * `commands=[]`, which says nothing about why. + */ +internal fun serverCommand(root: String?, configured: String): List? { + val exe = findExecutable(root, configured, listOf("ludic-lsp", "ludic-lsp.exe"), SERVER_SUBDIRS) + return exe?.let { listOf(it, "--stdio") } +} + +/** Where the toolchain is looked for, relative to the project root. */ +internal val SERVER_SUBDIRS = listOf("build", "tools/build", "bin", ".") +internal val COMPILER_SUBDIRS = listOf("build", "bin", ".") + +class LudicLanguageServerFactory : LanguageServerFactory { + override fun createConnectionProvider(project: Project): StreamConnectionProvider = + LudicConnectionProvider(project) + + override fun createLanguageClient(project: Project): LanguageClientImpl = + LanguageClientImpl(project) +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicSyntaxHighlighter.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicSyntaxHighlighter.kt new file mode 100644 index 00000000..f0da82f6 --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicSyntaxHighlighter.kt @@ -0,0 +1,76 @@ +package io.ludic.ide + +import com.intellij.lexer.Lexer +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors as D +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey +import com.intellij.openapi.editor.HighlighterColors +import com.intellij.openapi.fileTypes.SyntaxHighlighter +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase +import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.tree.IElementType + +/** + * Colours are all derived from the IDE's own semantic keys rather than hard + * coded, so Ludic looks native in whatever theme the user has, dark or light, + * without shipping a colour scheme. + */ +object LudicColors { + val COMMENT = key("LUDIC_COMMENT", D.LINE_COMMENT) + val STRING = key("LUDIC_STRING", D.STRING) + val NUMBER = key("LUDIC_NUMBER", D.NUMBER) + val KEYWORD = key("LUDIC_KEYWORD", D.KEYWORD) + val DECL_KEYWORD = key("LUDIC_DECL_KEYWORD", D.KEYWORD) + val CLAUSE = key("LUDIC_CLAUSE", D.METADATA) + val PRIMITIVE = key("LUDIC_PRIMITIVE", D.KEYWORD) + val PHASE = key("LUDIC_PHASE", D.STATIC_FIELD) + val BOOLEAN = key("LUDIC_BOOLEAN", D.KEYWORD) + val BUILTIN = key("LUDIC_BUILTIN", D.PREDEFINED_SYMBOL) + val TYPE_NAME = key("LUDIC_TYPE", D.CLASS_NAME) + val IDENTIFIER = key("LUDIC_IDENTIFIER", D.IDENTIFIER) + val ANNOTATION = key("LUDIC_ANNOTATION", D.METADATA) + val OPERATOR = key("LUDIC_OPERATOR", D.OPERATION_SIGN) + val BRACE = key("LUDIC_BRACE", D.BRACES) + val BRACKET = key("LUDIC_BRACKET", D.BRACKETS) + val PAREN = key("LUDIC_PAREN", D.PARENTHESES) + val COMMA = key("LUDIC_COMMA", D.COMMA) + val BAD = createTextAttributesKey("LUDIC_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER) + + private fun key(name: String, base: TextAttributesKey) = createTextAttributesKey(name, base) +} + +class LudicSyntaxHighlighter : SyntaxHighlighterBase() { + override fun getHighlightingLexer(): Lexer = LudicLexer() + + override fun getTokenHighlights(tokenType: IElementType): Array = pack( + when (tokenType) { + LudicTokens.COMMENT -> LudicColors.COMMENT + LudicTokens.STRING, LudicTokens.CHAR -> LudicColors.STRING + LudicTokens.NUMBER -> LudicColors.NUMBER + LudicTokens.KEYWORD -> LudicColors.KEYWORD + LudicTokens.DECL_KEYWORD -> LudicColors.DECL_KEYWORD + LudicTokens.CLAUSE -> LudicColors.CLAUSE + LudicTokens.PRIMITIVE -> LudicColors.PRIMITIVE + LudicTokens.PHASE -> LudicColors.PHASE + LudicTokens.BOOLEAN -> LudicColors.BOOLEAN + LudicTokens.BUILTIN -> LudicColors.BUILTIN + LudicTokens.TYPE_NAME -> LudicColors.TYPE_NAME + LudicTokens.IDENTIFIER -> LudicColors.IDENTIFIER + LudicTokens.ANNOTATION -> LudicColors.ANNOTATION + LudicTokens.OPERATOR -> LudicColors.OPERATOR + LudicTokens.BRACE -> LudicColors.BRACE + LudicTokens.BRACKET -> LudicColors.BRACKET + LudicTokens.PAREN -> LudicColors.PAREN + LudicTokens.COMMA -> LudicColors.COMMA + LudicTokens.BAD -> LudicColors.BAD + else -> null + } + ) +} + +class LudicSyntaxHighlighterFactory : SyntaxHighlighterFactory() { + override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter = + LudicSyntaxHighlighter() +} diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt new file mode 100644 index 00000000..268db1ab --- /dev/null +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt @@ -0,0 +1,81 @@ +package io.ludic.ide + +import com.intellij.psi.tree.IElementType +import com.intellij.psi.tree.IFileElementType + +/** + * One token type per thing the highlighter needs to tell apart. This is a + * lexer-only language on the JetBrains side: the token set is the whole grammar + * the platform sees, and ludic-lsp supplies everything structural. + */ +class LudicTokenType(debugName: String) : IElementType(debugName, LudicLanguage) + +object LudicTokens { + val FILE = IFileElementType(LudicLanguage) + + val COMMENT = LudicTokenType("COMMENT") + val STRING = LudicTokenType("STRING") + val CHAR = LudicTokenType("CHAR") + val NUMBER = LudicTokenType("NUMBER") + val IDENTIFIER = LudicTokenType("IDENTIFIER") + val TYPE_NAME = LudicTokenType("TYPE_NAME") // Capitalised: component, archetype, scene + val KEYWORD = LudicTokenType("KEYWORD") + val DECL_KEYWORD = LudicTokenType("DECL_KEYWORD") // game, component, system, fn, ... + val CLAUSE = LudicTokenType("CLAUSE") // phase, query, reads, writes, ... + val PRIMITIVE = LudicTokenType("PRIMITIVE") // int, fixed, bool, entity, str, ptr, void + val PHASE = LudicTokenType("PHASE") // Start, Update, Render, ... + val BOOLEAN = LudicTokenType("BOOLEAN") + val BUILTIN = LudicTokenType("BUILTIN") // runtime surface + compiler intrinsics + val ANNOTATION = LudicTokenType("ANNOTATION") // @deterministic + val OPERATOR = LudicTokenType("OPERATOR") + val BRACE = LudicTokenType("BRACE") + val BRACKET = LudicTokenType("BRACKET") + val PAREN = LudicTokenType("PAREN") + val COMMA = LudicTokenType("COMMA") + val BAD = LudicTokenType("BAD_CHARACTER") +} + +/** + * The vocabulary, mirroring tools/ludic-tools/ludic_syntax.h. When the language + * grows a keyword both sides change together; that header is the reference. + */ +object LudicVocabulary { + val DECL = setOf( + "game", "module", "import", "component", "struct", "archetype", "ui", "scene", "layer", + "const", "var", "export", "fn", "pure", "extern", "system", "edge", "start", "on" + ) + val CLAUSE = setOf( + "phase", "query", "reads", "writes", "needs", "uses", + "requires", "ensures", "invariant", "effects" + ) + val STMT = setOf( + "let", "return", "if", "else", "when", "while", "for", "in", "spawn", "despawn", + "match", "machine", "state", "become", "enter", "where", "and", "or", "not", + "break", "continue", "new" + ) + val PRIMITIVES = setOf("int", "fixed", "bool", "entity", "str", "ptr", "void") + val PHASES = setOf("Start", "Input", "FixedUpdate", "Update", "LateUpdate", "Render") + val WIDGETS = setOf("panel", "col", "row", "label", "button", "image", "spacer") + + val BUILTINS = setOf( + "min", "max", "abs", "clamp", "seed", "rng_range", "rng_chance", "fx", "flr", + "map_size", "map_row", "tile", "clear", "present", "fill_rect", "frame_rect", + "put_px", "text", "text_int", "font_load", "text_ttf", "text_w", "text_h", + "image_load", "draw_image", "draw_image_scaled", "draw_9slice", "load_png", + "load_sprites", "draw_sprite", "draw_sprite_scaled", "ui_build", "ui_open", + "ui_tick", "ui_render", "ui_clicked", "ui_set_text", "ui_set_int", "ui_focus", + "ui_focused", "ui_visible", "key", "reg", "setreg", "self", "save", "load", + "status", "print_int", "quit", + // compiler intrinsics: the floor the Ludic-written runtime stands on + "mem_alloc", "mem_realloc", "mem_free", "mem_copy", "mem_set", "peek8", "poke8", "peek32", + "os_argc", "os_arg", "file_stderr", + "poke32", "peekp", "pokep", "peekf", "pokef", "ptr_add", "ptr_null", + "ptr_is_null", "as_fixed", "as_int", "file_open", "file_read", "file_write", + "file_seek", "file_tell", "file_close", "read_byte", "write_byte", "print_str", + "str_len", "shl", "shr", "band", "bor", "bxor", "bnot", "os_exit", "os_time", + "is_windowed", "game_title", "win_open", "win_poll", "win_present", + "win_running", "win_close" + ) + + fun isKeyword(w: String) = w in DECL || w in CLAUSE || w in STMT +} diff --git a/tools/editors/jetbrains/src/main/resources/META-INF/ludic-markdown.xml b/tools/editors/jetbrains/src/main/resources/META-INF/ludic-markdown.xml new file mode 100644 index 00000000..b9b7ff56 --- /dev/null +++ b/tools/editors/jetbrains/src/main/resources/META-INF/ludic-markdown.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/tools/editors/jetbrains/src/main/resources/META-INF/plugin.xml b/tools/editors/jetbrains/src/main/resources/META-INF/plugin.xml new file mode 100644 index 00000000..ec25a803 --- /dev/null +++ b/tools/editors/jetbrains/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,78 @@ + + io.ludic.ide + Ludic + Ludic + + Language support for Ludic, the AI-first, ECS-native game language.

+
    +
  • Syntax highlighting, brace matching, commenting and folding, implemented natively so a + .ludic file is coloured with no external process.
  • +
  • Completion, diagnostics, hover, go-to-definition, find usages, rename and formatting via + the ludic-lsp language server, through LSP4IJ, so this works in Community + editions as well as the paid IDEs.
  • +
  • Errors from the Ludic compiler itself, reported on save.
  • +
  • Highlighting of ```ludic fenced blocks in Markdown.
  • +
+

Set the paths under Settings → Languages & Frameworks → Ludic, or leave + them blank to use build/ludic-lsp and build/ludicc under the + project root.

+ ]]>
+ + com.intellij.modules.platform + com.redhat.devtools.lsp4ij + + org.intellij.plugins.markdown + + + + + + + + + + + + + + + + + + + + tools/build-tools.sh. + ]]> + + + + + +
diff --git a/tools/editors/jetbrains/src/main/resources/icons/ludic.svg b/tools/editors/jetbrains/src/main/resources/icons/ludic.svg new file mode 100644 index 00000000..afae6c40 --- /dev/null +++ b/tools/editors/jetbrains/src/main/resources/icons/ludic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/FindExecutableTest.kt b/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/FindExecutableTest.kt new file mode 100644 index 00000000..74d5caee --- /dev/null +++ b/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/FindExecutableTest.kt @@ -0,0 +1,155 @@ +package io.ludic.ide + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.io.File + +/** + * Locating `ludic-lsp` is the single point where the whole language server can + * fail silently: if this returns null the provider starts with an empty command + * list, LSP4IJ reports `commands=[]`, and nothing in that message points at the + * cause. It shipped broken once for exactly that reason, so it gets tests. + */ +class FindExecutableTest { + + @get:Rule + val tmp = TemporaryFolder() + + private val names = listOf("ludic-lsp", "ludic-lsp.exe") + + private fun executableAt(vararg segments: String): File { + val f = File(tmp.root, segments.joinToString(File.separator)) + f.parentFile.mkdirs() + f.writeText("#!/bin/sh\n") + check(f.setExecutable(true)) + return f + } + + @Test + fun `finds the binary that build-tools_sh produces`() { + val exe = executableAt("build", "ludic-lsp") + assertEquals(exe.absolutePath, findExecutable(tmp.root.path, "", names, SERVER_SUBDIRS)) + } + + @Test + fun `a project root that is a subdirectory of the repo finds nothing`() { + // The bug that shipped: the IDE was opened on /tools, so the + // lookup searched /tools/build and came back empty while + // /build/ludic-lsp sat there the whole time. + executableAt("build", "ludic-lsp") + val subdir = File(tmp.root, "tools").apply { mkdirs() } + assertNull( + "must not silently resolve from an unrelated root", + findExecutable(subdir.path, "", names, SERVER_SUBDIRS) + ) + } + + @Test + fun `search order prefers build over the other candidates`() { + executableAt("bin", "ludic-lsp") + val preferred = executableAt("build", "ludic-lsp") + assertEquals(preferred.absolutePath, findExecutable(tmp.root.path, "", names, SERVER_SUBDIRS)) + } + + @Test + fun `every documented subdirectory is actually searched`() { + for (dir in SERVER_SUBDIRS) { + val fresh = TemporaryFolder().apply { create() } + val f = File(fresh.root, "$dir${File.separator}ludic-lsp") + f.parentFile.mkdirs() + f.writeText("#!/bin/sh\n") + f.setExecutable(true) + assertEquals( + "subdir '$dir' is advertised but not searched", + f.canonicalPath, + File(findExecutable(fresh.root.path, "", names, SERVER_SUBDIRS)!!).canonicalPath + ) + fresh.delete() + } + } + + @Test + fun `an explicitly configured path wins over anything found by search`() { + executableAt("build", "ludic-lsp") + val custom = executableAt("elsewhere", "my-lsp") + assertEquals(custom.absolutePath, findExecutable(tmp.root.path, custom.absolutePath, names, SERVER_SUBDIRS)) + } + + @Test + fun `a configured path that does not exist fails instead of falling back`() { + // Silently ignoring the setting and using a different binary would be + // worse than failing: the user asked for a specific server. + executableAt("build", "ludic-lsp") + assertNull(findExecutable(tmp.root.path, File(tmp.root, "nope").path, names, SERVER_SUBDIRS)) + } + + @Test + fun `a non-executable file is not accepted`() { + val f = File(tmp.root, "build/ludic-lsp") + f.parentFile.mkdirs() + f.writeText("not executable") + f.setExecutable(false) + assertNull(findExecutable(tmp.root.path, "", names, SERVER_SUBDIRS)) + } + + @Test + fun `a directory named like the binary is not accepted`() { + File(tmp.root, "build/ludic-lsp").mkdirs() + assertNull(findExecutable(tmp.root.path, "", names, SERVER_SUBDIRS)) + } + + @Test + fun `a null project root still allows a PATH lookup`() { + // No exception, no crash: the default project has no basePath. + findExecutable(null, "", names, SERVER_SUBDIRS) + } + + @Test + fun `the real repository layout resolves`() { + // Guards the arrangement the plugin actually ships against: run + // ./tools/build-tools.sh and opening the repo root must just work. + val repoRoot = File(System.getProperty("user.dir")).parentFile.parentFile.parentFile + val built = File(repoRoot, "build/ludic-lsp") + if (!built.isFile) return // toolchain not built in this checkout + val found = findExecutable(repoRoot.path, "", names, SERVER_SUBDIRS) + assertTrue("repo root must resolve to build/ludic-lsp", found != null) + assertEquals(built.canonicalPath, File(found!!).canonicalPath) + } +} + +/** + * The launch command itself. LSP4IJ only ever reports `commands=[...]`, so if + * this list is wrong the failure surfaces with no explanation at all. + */ +class ServerCommandTest { + + private val repoRoot: File = + File(System.getProperty("user.dir")).parentFile.parentFile.parentFile + + @Test + fun `the repository root produces a runnable stdio command`() { + val built = File(repoRoot, "build/ludic-lsp") + if (!built.isFile) return // toolchain not built in this checkout + + val cmd = serverCommand(repoRoot.path, "") + assertEquals(listOf(built.canonicalPath, "--stdio"), cmd!!.let { listOf(File(it[0]).canonicalPath, it[1]) }) + + // and it must actually be executable, not merely present + val proc = ProcessBuilder(cmd[0], "--version").redirectErrorStream(true).start() + val out = proc.inputStream.bufferedReader().readText().trim() + proc.waitFor() + assertTrue("expected a version banner, got '$out'", out.startsWith("ludic-lsp")) + } + + @Test + fun `a root without the toolchain yields no command rather than an empty one`() { + // The distinction that matters: null lets start() throw an explanatory + // error; an empty list is what produced the useless `commands=[]`. + val cmd = serverCommand(File(repoRoot, "tools/editors").path, "") + assertTrue("must be null, not an empty list", cmd == null || cmd.isNotEmpty()) + } +} diff --git a/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/LudicLexerTest.kt b/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/LudicLexerTest.kt new file mode 100644 index 00000000..b5e72bbf --- /dev/null +++ b/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/LudicLexerTest.kt @@ -0,0 +1,169 @@ +package io.ludic.ide + +import com.intellij.psi.TokenType +import com.intellij.psi.tree.IElementType +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +/** + * Syntax highlighting is the lexer plus a colour map, so this is where a + * highlighting regression actually shows up. These are plain JUnit tests: the + * lexer has no platform dependencies, so they run in milliseconds without + * booting an IDE. + */ +class LudicLexerTest { + + private fun lex(text: String): List> { + val lexer = LudicLexer() + lexer.start(text, 0, text.length, 0) + val out = mutableListOf>() + while (true) { + val t = lexer.tokenType ?: break + if (t != TokenType.WHITE_SPACE) { + out += t to text.substring(lexer.tokenStart, lexer.tokenEnd) + } + lexer.advance() + } + return out + } + + private fun typesOf(text: String) = lex(text).map { it.first } + + @Test + fun `declaration keywords are distinct from statement keywords`() { + assertEquals( + listOf(LudicTokens.DECL_KEYWORD, LudicTokens.TYPE_NAME, LudicTokens.BRACE), + typesOf("game Hello {") + ) + assertEquals(LudicTokens.KEYWORD, typesOf("if x { }").first()) + } + + @Test + fun `clause keywords are their own class`() { + // `phase` and `query` colour differently from `if`/`let`, which is the + // whole reason a system signature reads as a signature. + assertEquals( + listOf(LudicTokens.DECL_KEYWORD, LudicTokens.TYPE_NAME, LudicTokens.CLAUSE, LudicTokens.PHASE), + typesOf("system Move phase FixedUpdate") + ) + } + + @Test + fun `primitive types and phases are not plain identifiers`() { + assertEquals(LudicTokens.PRIMITIVE, typesOf("int").single()) + assertEquals(LudicTokens.PRIMITIVE, typesOf("fixed").single()) + assertEquals(LudicTokens.PHASE, typesOf("LateUpdate").single()) + assertEquals(LudicTokens.BOOLEAN, typesOf("true").single()) + } + + @Test + fun `builtins are recognised, unknown calls are not`() { + assertEquals(LudicTokens.BUILTIN, typesOf("rng_chance").single()) + assertEquals(LudicTokens.BUILTIN, typesOf("peek32").single()) // intrinsic + assertEquals(LudicTokens.IDENTIFIER, typesOf("my_helper").single()) + } + + @Test + fun `capitalised words read as type names`() { + assertEquals(LudicTokens.TYPE_NAME, typesOf("Pos").single()) + assertEquals(LudicTokens.IDENTIFIER, typesOf("pos").single()) + } + + @Test + fun `comments run to end of line and keep their text`() { + val toks = lex("let a = 1 # keep me\nlet b = 2") + val comment = toks.first { it.first == LudicTokens.COMMENT } + assertEquals("# keep me", comment.second) + // the newline ends it: the next line is code again + assertEquals(LudicTokens.KEYWORD, toks[toks.indexOf(comment) + 1].first) + } + + @Test + fun `strings handle escapes and do not swallow the rest of the file`() { + val toks = lex(""""a\"b" 42""") + assertEquals(LudicTokens.STRING, toks[0].first) + assertEquals(""""a\"b"""", toks[0].second) + assertEquals(LudicTokens.NUMBER, toks[1].first) + } + + @Test + fun `an unterminated string stops at the newline`() { + // A half-typed string must not colour the whole rest of the file. + val toks = lex("let s = \"oops\nlet t = 1") + assertEquals(LudicTokens.STRING, toks[3].first) + assertEquals("\"oops", toks[3].second) + assertEquals(LudicTokens.KEYWORD, toks[4].first) + } + + @Test + fun `numbers cover hex, fixed-point and the range operator`() { + assertEquals(LudicTokens.NUMBER, typesOf("0x1affff").single()) + assertEquals(LudicTokens.NUMBER, typesOf("1.5").single()) + // `0..10` is two ints and a range op, not a malformed float + assertEquals( + listOf(LudicTokens.NUMBER, LudicTokens.OPERATOR, LudicTokens.NUMBER), + typesOf("0..10") + ) + assertEquals("..", lex("0..10")[1].second) + } + + @Test + fun `annotations lex as one token including the sigil`() { + val toks = lex("@deterministic") + assertEquals(LudicTokens.ANNOTATION, toks.single().first) + assertEquals("@deterministic", toks.single().second) + } + + @Test + fun `two-character operators beat one-character ones`() { + assertEquals(listOf("->"), lex("->").map { it.second }) + assertEquals(listOf("=>"), lex("=>").map { it.second }) + assertEquals(listOf("!="), lex("!=").map { it.second }) + assertEquals(listOf("<="), lex("<=").map { it.second }) + } + + @Test + fun `the lexer always terminates and covers every character`() { + // The IDE lexes half-typed text constantly; a lexer that stalls hangs + // the editor, and one that skips bytes corrupts every offset after it. + val nasty = "game X { component ¿ { a: int = ' } # é\n query [{Tag}] \"unclosed" + val lexer = LudicLexer() + lexer.start(nasty, 0, nasty.length, 0) + var covered = 0 + var guard = 0 + while (lexer.tokenType != null) { + assertTrue("token must advance", lexer.tokenEnd > lexer.tokenStart) + assertEquals("no gaps between tokens", covered, lexer.tokenStart) + covered = lexer.tokenEnd + lexer.advance() + check(guard++ < 10_000) { "lexer did not terminate" } + } + assertEquals("every character consumed", nasty.length, covered) + } + + @Test + fun `a real source file lexes with no bad characters`() { + val src = """ + game Hello { + component Pos { x: int = 0, y: int = 0 } + archetype Mob { Pos } + + system Move phase FixedUpdate + query (p) [Pos, {Player}] where p.x > 0 + { + p.x = p.x + 1 + for i in 0 .. 10 { print_int(i) } + } + + ui Menu { + panel id=Root w=288 pad=16 { + button id=Go text="Go" size=16 + } + } + } + """.trimIndent() + val bad = lex(src).filter { it.first == LudicTokens.BAD } + assertTrue("unexpected bad characters: ${bad.map { it.second }}", bad.isEmpty()) + } +} diff --git a/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/LudicPlatformTest.kt b/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/LudicPlatformTest.kt new file mode 100644 index 00000000..7a27e4d8 --- /dev/null +++ b/tools/editors/jetbrains/src/test/kotlin/io/ludic/ide/LudicPlatformTest.kt @@ -0,0 +1,124 @@ +package io.ludic.ide + +import com.intellij.lang.LanguageParserDefinitions +import com.intellij.openapi.fileTypes.FileTypeManager +import com.intellij.psi.PsiFile +import com.intellij.testFramework.fixtures.BasePlatformTestCase + +/** + * The IDE-side wiring, exercised in a real (headless) platform fixture. These + * cover the things that make a file feel like a supported language rather than + * plain text: the extension is claimed, a PSI tree is built (which is what + * indexing and Markdown injection both stand on), folds appear, braces pair up + * and Ctrl+/ comments. + */ +class LudicPlatformTest : BasePlatformTestCase() { + + private val sample = """ + game Hello { + component Pos { x: int = 0, y: int = 0 } + archetype Mob { Pos } + + # move everything that has a position + system Move phase FixedUpdate + query (p) [Pos, {Player}] + { + p.x = p.x + 1 + } + } + """.trimIndent() + + private fun ludicFile(text: String = sample): PsiFile = + myFixture.configureByText("sample.ludic", text) + + fun testExtensionIsClaimedByTheLudicFileType() { + val type = FileTypeManager.getInstance().getFileTypeByExtension("ludic") + assertEquals("Ludic", type.name) + assertEquals(LudicFileType, type) + } + + fun testFileTypeIsNotBinaryAndUsesUtf8() { + assertFalse(LudicFileType.isBinary) + assertEquals("ludic", LudicFileType.defaultExtension) + } + + fun testParserDefinitionIsRegisteredForTheLanguage() { + // Markdown fence injection needs a PSI tree, so this registration is + // what makes ```ludic blocks highlight in a .md file. + val def = LanguageParserDefinitions.INSTANCE.forLanguage(LudicLanguage) + assertNotNull("no ParserDefinition registered for Ludic", def) + } + + fun testPsiTreeIsBuiltAndCoversTheWholeFile() { + val file = ludicFile() + assertEquals(LudicLanguage, file.language) + assertEquals(sample, file.text) + assertTrue("expected a non-empty PSI tree", file.children.isNotEmpty()) + // every character must be reachable through the tree, or offsets drift + assertEquals(sample.length, file.textLength) + } + + fun testHighlighterAssignsColoursToEveryMeaningfulToken() { + val highlighter = LudicSyntaxHighlighter() + val coloured = listOf( + LudicTokens.DECL_KEYWORD, LudicTokens.KEYWORD, LudicTokens.CLAUSE, + LudicTokens.PRIMITIVE, LudicTokens.PHASE, LudicTokens.BOOLEAN, + LudicTokens.BUILTIN, LudicTokens.TYPE_NAME, LudicTokens.STRING, + LudicTokens.NUMBER, LudicTokens.COMMENT, LudicTokens.ANNOTATION, + LudicTokens.OPERATOR, LudicTokens.BRACE, LudicTokens.BRACKET, + LudicTokens.PAREN, LudicTokens.COMMA, LudicTokens.IDENTIFIER + ) + for (token in coloured) { + val keys = highlighter.getTokenHighlights(token) + assertTrue("no colour mapped for $token", keys.isNotEmpty()) + } + } + + fun testFoldingCollapsesMultiLineBlocksOnly() { + val file = ludicFile() + val regions = LudicFoldingBuilder().buildFoldRegions(file.node, file.viewProvider.document!!) + + // The sample has exactly two blocks that span lines: the `game` body and + // the `system` body. `component Pos { … }`, `archetype Mob { … }` and the + // `{Player}` query filter all fit on one line, and folding a single line + // gains nothing, so they are deliberately skipped. + assertEquals("multi-line blocks only", 2, regions.size) + + val outermost = regions.maxByOrNull { it.range.length }!! + assertEquals("outermost fold starts at the game block's brace", + sample.indexOf('{'), outermost.range.startOffset) + assertEquals("outermost fold ends at the last brace", + sample.length, outermost.range.endOffset) + + for (r in regions) { + assertTrue("fold region must be non-empty", r.range.length > 0) + assertEquals("{...}", LudicFoldingBuilder().getPlaceholderText(file.node)) + } + } + + fun testCommenterUsesHashWithASpace() { + // The trailing space is deliberate: Ctrl+/ should produce "# code", + // which is how every comment in the runtime and examples is written. + val commenter = LudicCommenter() + assertEquals("# ", commenter.lineCommentPrefix) + assertNull("Ludic has no block comments", commenter.blockCommentPrefix) + } + + fun testBraceMatcherPairsAllThreeBracketKinds() { + val matcher = LudicBraceMatcher() + val pairs = matcher.pairs + val open = pairs.map { it.leftBraceType }.toSet() + assertTrue(open.contains(LudicTokens.BRACE)) + assertTrue(open.contains(LudicTokens.BRACKET)) + assertTrue(open.contains(LudicTokens.PAREN)) + } + + fun testHalfTypedFileStillProducesAPsiTree() { + // The IDE must survive what a file looks like mid-keystroke; a parser + // that throws here takes highlighting and indexing down with it. + val broken = "game X {\n component P { x: int =\n system" + val file = myFixture.configureByText("broken.ludic", broken) + assertEquals(broken.length, file.textLength) + assertEquals(LudicLanguage, file.language) + } +} diff --git a/tools/editors/neovim/lua/ludic.lua b/tools/editors/neovim/lua/ludic.lua new file mode 100644 index 00000000..67f12e38 --- /dev/null +++ b/tools/editors/neovim/lua/ludic.lua @@ -0,0 +1,86 @@ +-- Ludic support for Neovim (0.9+), with no plugin manager and no dependencies. +-- +-- :lua require('ludic').setup() +-- -- or, from init.lua: +-- vim.opt.runtimepath:append('/path/to/gpp/tools/editors/neovim') +-- require('ludic').setup({ server = '/path/to/gpp/build/ludic-lsp' }) +-- +-- Highlighting here comes from the language server's semantic tokens, which +-- Neovim applies natively -- there is no tree-sitter grammar to install and no +-- second copy of the vocabulary to keep in sync. + +local M = {} + +local function find_executable(names, roots, subdirs) + for _, root in ipairs(roots) do + for _, sub in ipairs(subdirs) do + for _, name in ipairs(names) do + local p = root .. '/' .. sub .. '/' .. name + if vim.fn.executable(p) == 1 then return p end + end + end + end + for _, name in ipairs(names) do + if vim.fn.executable(name) == 1 then return name end + end + return nil +end + +function M.setup(opts) + opts = opts or {} + + -- .ludic files are Ludic + vim.filetype.add({ extension = { ludic = 'ludic' } }) + + vim.api.nvim_create_autocmd('FileType', { + pattern = 'ludic', + callback = function() + vim.bo.commentstring = '# %s' + vim.bo.comments = ':#' + vim.bo.expandtab = true + vim.bo.shiftwidth = opts.indent or 2 + vim.bo.tabstop = opts.indent or 2 + end, + }) + + local root_markers = { 'build.sh', 'LANGUAGE.md', '.git' } + + local function root_dir(fname) + local found = vim.fs.find(root_markers, { path = vim.fs.dirname(fname), upward = true })[1] + return found and vim.fs.dirname(found) or vim.fs.dirname(fname) + end + + vim.api.nvim_create_autocmd('FileType', { + -- markdown is included on purpose: ```ludic fences get diagnostics and + -- semantic highlighting like any source file + pattern = { 'ludic', 'markdown' }, + callback = function(args) + local root = root_dir(vim.api.nvim_buf_get_name(args.buf)) + local server = opts.server or find_executable( + { 'ludic-lsp' }, { root }, { 'build', 'tools/build', 'bin', '.' }) + if not server then return end + local compiler = opts.compiler or find_executable( + { 'ludicc' }, { root }, { 'build', 'bin', '.' }) or '' + + vim.lsp.start({ + name = 'ludic-lsp', + cmd = { server, '--stdio' }, + root_dir = root, + init_options = { + compilerPath = compiler, + compilerDiagnostics = opts.compiler_diagnostics ~= false, + indentSize = opts.indent or 2, + }, + }, { bufnr = args.buf }) + end, + }) + + if opts.format_on_save ~= false then + vim.api.nvim_create_autocmd('BufWritePre', { + pattern = { '*.ludic' }, + callback = function() vim.lsp.buf.format({ async = false, timeout_ms = 2000 }) end, + }) + end +end + +return M diff --git a/tools/editors/shared/language-configuration.json b/tools/editors/shared/language-configuration.json new file mode 100644 index 00000000..6fb5c01a --- /dev/null +++ b/tools/editors/shared/language-configuration.json @@ -0,0 +1,31 @@ +{ + "comment": "Editor mechanics that are not highlighting and not the language server: comments, bracket pairs, auto-closing, indentation triggers. VS Code reads this file directly; the JetBrains plugin implements the same rules natively; other editors can transcribe it.", + "comments": { + "lineComment": "#" + }, + "brackets": [["{", "}"], ["[", "]"], ["(", ")"]], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { "open": "\"", "close": "\"", "notIn": ["string", "comment"] } + ], + "surroundingPairs": [["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""]], + "indentationRules": { + "increaseIndentPattern": "^((?!//).)*(\\{[^}\"']*|\\([^)\"']*|\\[[^\\]\"']*)$", + "decreaseIndentPattern": "^\\s*[}\\])].*$" + }, + "onEnterRules": [ + { + "beforeText": "^\\s*#.*$", + "action": { "indent": "none", "appendText": "# " } + } + ], + "wordPattern": "[A-Za-z_][A-Za-z0-9_]*", + "folding": { + "markers": { + "start": "^\\s*#\\s*region\\b", + "end": "^\\s*#\\s*endregion\\b" + } + } +} diff --git a/tools/editors/shared/ludic.markdown-injection.json b/tools/editors/shared/ludic.markdown-injection.json new file mode 100644 index 00000000..15931c4c --- /dev/null +++ b/tools/editors/shared/ludic.markdown-injection.json @@ -0,0 +1,27 @@ +{ + "scopeName": "markdown.ludic.codeblock", + "comment": "Injects Ludic highlighting into ```ludic fences in Markdown. Any TextMate-based editor (VS Code, Sublime, JetBrains' TextMate bundles, Zed) picks this up; JetBrains' native Markdown support gets the same thing for free from the registered `Ludic` language ID, and ludic-lsp will also serve semantic tokens and diagnostics for the fence bodies in a .md file.", + "injectionSelector": "L:text.html.markdown", + "patterns": [{ "include": "#ludic-code-block" }], + "repository": { + "ludic-code-block": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ludic)((\\s+|:|,|\\{|\\?)[^`~]*)?)$", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { "name": "punctuation.definition.markdown" }, + "4": { "name": "fenced_code.block.language.markdown" }, + "5": { "name": "fenced_code.block.language.attributes.markdown" } + }, + "endCaptures": { "3": { "name": "punctuation.definition.markdown" } }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.ludic", + "patterns": [{ "include": "source.ludic" }] + } + ] + } + } +} diff --git a/tools/editors/shared/ludic.tmLanguage.json b/tools/editors/shared/ludic.tmLanguage.json new file mode 100644 index 00000000..8b99e208 --- /dev/null +++ b/tools/editors/shared/ludic.tmLanguage.json @@ -0,0 +1,241 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Ludic", + "scopeName": "source.ludic", + "fileTypes": ["ludic"], + "comment": "Static grammar for Ludic. It is the fallback: when ludic-lsp is running, its semantic tokens refine everything here with real name resolution. Generated shapes are kept in sync with tools/ludic-tools/ludic_syntax.h.", + "patterns": [ + { "include": "#comment" }, + { "include": "#declaration" }, + { "include": "#query" }, + { "include": "#string" }, + { "include": "#number" }, + { "include": "#annotation" }, + { "include": "#keyword" }, + { "include": "#widget" }, + { "include": "#builtin" }, + { "include": "#member" }, + { "include": "#call" }, + { "include": "#typename" }, + { "include": "#operator" } + ], + "repository": { + "comment": { + "match": "#.*$", + "name": "comment.line.number-sign.ludic" + }, + "string": { + "patterns": [ + { + "name": "string.quoted.double.ludic", + "begin": "\"", + "end": "\"", + "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ludic" } }, + "endCaptures": { "0": { "name": "punctuation.definition.string.end.ludic" } }, + "patterns": [{ "name": "constant.character.escape.ludic", "match": "\\\\." }] + }, + { + "name": "string.quoted.single.ludic", + "match": "'(\\\\.|[^'\\\\])'" + } + ] + }, + "number": { + "patterns": [ + { "name": "constant.numeric.hex.ludic", "match": "\\b0[xX][0-9a-fA-F]+\\b" }, + { "name": "constant.numeric.fixed.ludic", "match": "\\b[0-9]+\\.[0-9]+\\b" }, + { "name": "constant.numeric.integer.ludic", "match": "\\b[0-9]+\\b" } + ] + }, + "annotation": { + "name": "entity.name.function.decorator.ludic", + "match": "@[A-Za-z_][A-Za-z0-9_]*" + }, + "declaration": { + "patterns": [ + { + "match": "\\b(game|module)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.unit.ludic" }, + "2": { "name": "entity.name.type.unit.ludic" } + } + }, + { + "match": "\\b(component)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.component.ludic" }, + "2": { "name": "entity.name.type.component.ludic" } + } + }, + { + "match": "\\b(archetype)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.archetype.ludic" }, + "2": { "name": "entity.name.type.archetype.ludic" } + } + }, + { + "match": "\\b(scene)\\s+([A-Za-z_][A-Za-z0-9_]*)(\\s+start)?", + "captures": { + "1": { "name": "storage.type.scene.ludic" }, + "2": { "name": "entity.name.type.scene.ludic" }, + "3": { "name": "keyword.other.start.ludic" } + } + }, + { + "match": "\\b(layer|ui)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.ludic" }, + "2": { "name": "entity.name.type.ludic" } + } + }, + { + "match": "\\b(edge\\s+)?(system)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.modifier.edge.ludic" }, + "2": { "name": "storage.type.system.ludic" }, + "3": { "name": "entity.name.function.system.ludic" } + } + }, + { + "match": "\\b(export\\s+|pure\\s+)?(extern\\s+)?(fn)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.modifier.ludic" }, + "2": { "name": "storage.modifier.extern.ludic" }, + "3": { "name": "storage.type.function.ludic" }, + "4": { "name": "entity.name.function.ludic" } + } + }, + { + "match": "\\b(const|var|let)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.ludic" }, + "2": { "name": "variable.other.definition.ludic" } + } + }, + { + "match": "\\b(state)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.state.ludic" }, + "2": { "name": "entity.name.constant.state.ludic" } + } + }, + { + "match": "\\b(import)\\s+(?=\")", + "captures": { "1": { "name": "keyword.control.import.ludic" } } + }, + { + "match": "\\b(phase)\\s+(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b", + "captures": { + "1": { "name": "keyword.other.clause.ludic" }, + "2": { "name": "constant.language.phase.ludic" } + } + }, + { + "match": "\\b(enter)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.enter.ludic" }, + "2": { "name": "entity.name.type.scene.ludic" } + } + }, + { + "match": "\\b(spawn)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.spawn.ludic" }, + "2": { "name": "entity.name.type.archetype.ludic" } + } + } + ] + }, + "query": { + "comment": "Inside a query's brackets a bare word names a component and {Word} is a filter that does not bind.", + "begin": "\\b(query)\\s*(\\[)", + "beginCaptures": { + "1": { "name": "keyword.other.query.ludic" }, + "2": { "name": "punctuation.section.brackets.begin.ludic" } + }, + "end": "(\\])", + "endCaptures": { "1": { "name": "punctuation.section.brackets.end.ludic" } }, + "patterns": [ + { + "match": "(\\{)\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*(\\})", + "captures": { + "1": { "name": "punctuation.section.braces.begin.ludic" }, + "2": { "name": "entity.name.type.tag.ludic" }, + "3": { "name": "punctuation.section.braces.end.ludic" } + } + }, + { "name": "entity.name.type.component.ludic", "match": "\\b[A-Za-z_][A-Za-z0-9_]*\\b" }, + { "name": "punctuation.separator.ludic", "match": "," } + ] + }, + "keyword": { + "patterns": [ + { "name": "keyword.control.ludic", "match": "\\b(if|else|when|while|for|in|match|machine|become|enter|return|spawn|despawn|where|break|continue|new)\\b" }, + { "name": "keyword.operator.logical.ludic", "match": "\\b(and|or|not)\\b" }, + { "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|reads|writes|needs|uses|requires|ensures|invariant|effects|on)\\b" }, + { "name": "keyword.other.ludic", "match": "\\b(import|export|pure|extern|start|edge)\\b" }, + { "name": "storage.type.ludic", "match": "\\b(game|module|component|archetype|ui|scene|layer|const|var|let|fn|system|state)\\b" }, + { "name": "support.type.primitive.ludic", "match": "\\b(int|fixed|bool|entity|str|ptr|void)\\b" }, + { "name": "constant.language.boolean.ludic", "match": "\\b(true|false)\\b" }, + { "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" } + ] + }, + "widget": { + "patterns": [ + { + "comment": "widget types, recognised by the props or the child block that follow them", + "name": "support.class.widget.ludic", + "match": "\\b(panel|col|row|label|button|image|spacer)\\b(?=\\s*(\\{|[a-z][A-Za-z0-9_]*\\s*=|$))" + }, + { + "comment": "widget props are written tight (id=Root); an assignment is written x = 1", + "match": "\\b([a-z][A-Za-z0-9_]*)(=)(?!=)", + "captures": { + "1": { "name": "variable.parameter.widget.ludic" }, + "2": { "name": "keyword.operator.assignment.ludic" } + } + } + ] + }, + "builtin": { + "patterns": [ + { + "comment": "the runtime surface — every name here resolves to rt_ in runtime/native", + "name": "support.function.builtin.ludic", + "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|load_png|load_sprites|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|setreg|self|save|load|status|print_int|quit)\\b(?=\\s*\\()" + }, + { + "comment": "compiler intrinsics — these lower straight to libc or the OS", + "name": "support.function.intrinsic.ludic", + "match": "\\b(mem_alloc|mem_realloc|mem_free|mem_copy|mem_set|peek8|poke8|peek32|poke32|peekp|pokep|peekf|pokef|ptr_add|ptr_null|ptr_is_null|as_fixed|as_int|file_open|file_read|file_write|file_seek|file_tell|file_close|read_byte|write_byte|print_str|str_len|shl|shr|band|bor|bxor|bnot|os_exit|os_time|os_argc|os_arg|file_stderr|is_windowed|game_title|win_open|win_poll|win_present|win_running|win_close)\\b(?=\\s*\\()" + } + ] + }, + "member": { + "match": "(\\.)([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "punctuation.accessor.ludic" }, + "2": { "name": "variable.other.property.ludic" } + } + }, + "call": { + "match": "\\b([A-Za-z_][A-Za-z0-9_]*)\\s*(?=\\()", + "name": "entity.name.function.call.ludic" + }, + "typename": { + "comment": "components, archetypes, scenes and UI handles are Capitalised by convention", + "name": "entity.name.type.ludic", + "match": "\\b[A-Z][A-Za-z0-9_]*\\b" + }, + "operator": { + "patterns": [ + { "name": "keyword.operator.arrow.ludic", "match": "->|=>" }, + { "name": "keyword.operator.range.ludic", "match": "\\.\\." }, + { "name": "keyword.operator.comparison.ludic", "match": "==|!=|<=|>=|<|>" }, + { "name": "keyword.operator.assignment.ludic", "match": "\\+=|-=|\\*=|/=|=" }, + { "name": "keyword.operator.arithmetic.ludic", "match": "[+\\-*/%]" } + ] + } + } +} diff --git a/tools/editors/sublime/README.md b/tools/editors/sublime/README.md new file mode 100644 index 00000000..129a1eba --- /dev/null +++ b/tools/editors/sublime/README.md @@ -0,0 +1,35 @@ +# Ludic for Sublime Text + +Sublime reads TextMate grammars directly, so the shared grammar works as-is. + +1. **Highlighting.** Copy `tools/editors/shared/ludic.tmLanguage.json` into your + `Packages/User/` directory, renamed to `Ludic.tmLanguage.json`. Sublime picks + up `.ludic` from the grammar's `fileTypes`. + +2. **Markdown fences.** Copy + `tools/editors/shared/ludic.markdown-injection.json` alongside it as + `Ludic Markdown.tmLanguage.json`. Sublime honours `injectionSelector`, so + ` ```ludic ` blocks in Markdown are highlighted with no further setup. + +3. **Everything else** comes from the language server. Install + [LSP](https://packagecontrol.io/packages/LSP), then add to + `Preferences -> Package Settings -> LSP -> Settings`: + +```json +{ + "clients": { + "ludic": { + "enabled": true, + "command": ["/path/to/gpp/build/ludic-lsp", "--stdio"], + "selector": "source.ludic | text.html.markdown", + "initializationOptions": { + "compilerPath": "/path/to/gpp/build/ludicc", + "compilerDiagnostics": true, + "indentSize": 2 + } + } + } +} +``` + +Format on save with `LSP-format-on-save`, or bind `lsp_format_document`. diff --git a/tools/editors/vscode/.vscodeignore b/tools/editors/vscode/.vscodeignore new file mode 100644 index 00000000..2f8bcccd --- /dev/null +++ b/tools/editors/vscode/.vscodeignore @@ -0,0 +1,12 @@ +.vscode/** +node_modules/** +!node_modules/vscode-languageclient/** +!node_modules/vscode-jsonrpc/** +!node_modules/vscode-languageserver-protocol/** +!node_modules/vscode-languageserver-types/** +!node_modules/semver/** +!node_modules/balanced-match/** +!node_modules/minimatch/** +!node_modules/brace-expansion/** +!node_modules/concat-map/** +**/*.map diff --git a/tools/editors/vscode/README.md b/tools/editors/vscode/README.md new file mode 100644 index 00000000..58598f1b --- /dev/null +++ b/tools/editors/vscode/README.md @@ -0,0 +1,54 @@ +# Ludic for VS Code + +Syntax highlighting, formatting, and full language-server support for **Ludic**, +the AI-first, ECS-native game language. See `LANGUAGE.md` in the Ludic repository +for the language reference. + +## What you get + +| | Source | +|---|---| +| Syntax highlighting | TextMate grammar, works with no build | +| Semantic highlighting | `ludic-lsp` — real name resolution, so a component reads differently from a local | +| Diagnostics | structural errors as you type; `ludicc`'s own errors on save | +| Completion | context-aware: fields after `.`, components inside `query [...]`, phases after `phase`, widgets inside `ui` | +| Hover | signatures and docs for builtins, intrinsics, and everything you declared | +| Go to definition / references / rename | across every file in the compilation unit, following `import` | +| Formatting | format-on-save, comment-preserving | +| Outline, folding, inlay hints, signature help | | +| ` ```ludic ` fences in Markdown | highlighted, checked, and formatted | + +## Setup + +Build the toolchain once, from the repository root: + +```bash +./tools/build-tools.sh +``` + +That produces `build/ludic-lsp` and `build/ludic-fmt`, which the extension finds +on its own. If you keep them elsewhere, set `ludic.server.path`. + +Format on save: + +```json +"[ludic]": { "editor.formatOnSave": true } +``` + +## Settings + +- `ludic.server.path` — where `ludic-lsp` lives. Empty = search `build/`, then `PATH`. +- `ludic.server.enabled` — turn the server off and keep only static highlighting. +- `ludic.compilerPath` — where `ludicc` lives, for on-save diagnostics. +- `ludic.compilerDiagnostics` — whether to run the compiler at all. +- `ludic.indentSize` — spaces per level for the formatter. +- `ludic.trace.server` — log LSP traffic (`Ludic: Show Language Server Log`). + +## Installing without publishing + +```bash +cd tools/editors/vscode +npm install +npx @vscode/vsce package +code --install-extension ludic-1.0.0.vsix +``` diff --git a/tools/editors/vscode/icons/ludic.svg b/tools/editors/vscode/icons/ludic.svg new file mode 100644 index 00000000..afae6c40 --- /dev/null +++ b/tools/editors/vscode/icons/ludic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tools/editors/vscode/language-configuration.json b/tools/editors/vscode/language-configuration.json new file mode 100644 index 00000000..6fb5c01a --- /dev/null +++ b/tools/editors/vscode/language-configuration.json @@ -0,0 +1,31 @@ +{ + "comment": "Editor mechanics that are not highlighting and not the language server: comments, bracket pairs, auto-closing, indentation triggers. VS Code reads this file directly; the JetBrains plugin implements the same rules natively; other editors can transcribe it.", + "comments": { + "lineComment": "#" + }, + "brackets": [["{", "}"], ["[", "]"], ["(", ")"]], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { "open": "\"", "close": "\"", "notIn": ["string", "comment"] } + ], + "surroundingPairs": [["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""]], + "indentationRules": { + "increaseIndentPattern": "^((?!//).)*(\\{[^}\"']*|\\([^)\"']*|\\[[^\\]\"']*)$", + "decreaseIndentPattern": "^\\s*[}\\])].*$" + }, + "onEnterRules": [ + { + "beforeText": "^\\s*#.*$", + "action": { "indent": "none", "appendText": "# " } + } + ], + "wordPattern": "[A-Za-z_][A-Za-z0-9_]*", + "folding": { + "markers": { + "start": "^\\s*#\\s*region\\b", + "end": "^\\s*#\\s*endregion\\b" + } + } +} diff --git a/tools/editors/vscode/package-lock.json b/tools/editors/vscode/package-lock.json new file mode 100644 index 00000000..52c906f9 --- /dev/null +++ b/tools/editors/vscode/package-lock.json @@ -0,0 +1,97 @@ +{ + "name": "ludic", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ludic", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "vscode-languageclient": "^9.0.1" + }, + "engines": { + "vscode": "^1.75.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", + "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", + "license": "MIT", + "dependencies": { + "minimatch": "^5.1.0", + "semver": "^7.3.7", + "vscode-languageserver-protocol": "3.17.5" + }, + "engines": { + "vscode": "^1.82.0" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + } + } +} diff --git a/tools/editors/vscode/package.json b/tools/editors/vscode/package.json new file mode 100644 index 00000000..96d2273d --- /dev/null +++ b/tools/editors/vscode/package.json @@ -0,0 +1,158 @@ +{ + "name": "ludic", + "displayName": "Ludic", + "description": "Ludic language support: syntax highlighting, formatting, and the ludic-lsp language server. Also highlights ```ludic fences in Markdown.", + "version": "1.0.0", + "publisher": "ludic", + "license": "MIT", + "engines": { + "vscode": "^1.75.0" + }, + "categories": [ + "Programming Languages", + "Formatters", + "Linters" + ], + "keywords": [ + "ludic", + "ecs", + "gamedev" + ], + "main": "./src/extension.js", + "activationEvents": [ + "onLanguage:ludic", + "onLanguage:markdown", + "workspaceContains:**/*.ludic" + ], + "contributes": { + "languages": [ + { + "id": "ludic", + "aliases": [ + "Ludic", + "ludic" + ], + "extensions": [ + ".ludic" + ], + "configuration": "./language-configuration.json", + "icon": { + "light": "./icons/ludic.svg", + "dark": "./icons/ludic.svg" + } + } + ], + "grammars": [ + { + "language": "ludic", + "scopeName": "source.ludic", + "path": "./syntaxes/ludic.tmLanguage.json" + }, + { + "scopeName": "markdown.ludic.codeblock", + "path": "./syntaxes/ludic.markdown-injection.json", + "injectTo": [ + "text.html.markdown" + ], + "embeddedLanguages": { + "meta.embedded.block.ludic": "ludic" + } + } + ], + "semanticTokenScopes": [ + { + "language": "ludic", + "scopes": { + "struct": [ + "entity.name.type.component.ludic" + ], + "class": [ + "entity.name.type.archetype.ludic" + ], + "namespace": [ + "entity.name.type.scene.ludic" + ], + "function.defaultLibrary": [ + "support.function.builtin.ludic" + ], + "enumMember.readonly.defaultLibrary": [ + "constant.language.phase.ludic" + ], + "decorator": [ + "entity.name.function.decorator.ludic" + ] + } + } + ], + "configuration": { + "title": "Ludic", + "properties": { + "ludic.server.path": { + "type": "string", + "default": "", + "markdownDescription": "Path to the `ludic-lsp` binary. Empty means: look in `build/ludic-lsp` under each workspace folder, then on `PATH`." + }, + "ludic.server.enabled": { + "type": "boolean", + "default": true, + "description": "Run the Ludic language server. Turn this off to keep only the static syntax highlighting." + }, + "ludic.compilerPath": { + "type": "string", + "default": "", + "markdownDescription": "Path to `ludicc`. The server shells out to it for authoritative diagnostics on save. Empty means `build/ludicc` under the workspace." + }, + "ludic.compilerDiagnostics": { + "type": "boolean", + "default": true, + "description": "Report errors from the Ludic compiler on save, in addition to the server's own structural checks." + }, + "ludic.indentSize": { + "type": "number", + "default": 2, + "description": "Spaces per indent level used by the formatter when the editor does not say otherwise." + }, + "ludic.trace.server": { + "type": "string", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "Log the traffic between VS Code and the Ludic language server." + } + } + }, + "commands": [ + { + "command": "ludic.restartServer", + "title": "Ludic: Restart Language Server" + }, + { + "command": "ludic.showOutput", + "title": "Ludic: Show Language Server Log" + } + ], + "configurationDefaults": { + "[ludic]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + "editor.semanticHighlighting.enabled": true + } + }, + "snippets": [ + { + "language": "ludic", + "path": "./snippets/ludic.json" + } + ] + }, + "dependencies": { + "vscode-languageclient": "^9.0.1" + }, + "repository": { + "type": "git", + "url": "https://example.invalid/ludic" + } +} diff --git a/tools/editors/vscode/snippets/ludic.json b/tools/editors/vscode/snippets/ludic.json new file mode 100644 index 00000000..2bcd3a36 --- /dev/null +++ b/tools/editors/vscode/snippets/ludic.json @@ -0,0 +1,96 @@ +{ + "game": { + "prefix": "game", + "body": ["game ${1:Name} {", "\t$0", "}"], + "description": "A game unit — compiles to an executable." + }, + "module": { + "prefix": "module", + "body": ["module ${1:Name} {", "\t$0", "}"], + "description": "A library unit — compiles to a shared library, no frame loop." + }, + "component": { + "prefix": "component", + "body": ["component ${1:Name} { ${2:x}: ${3:int} = ${4:0} }"], + "description": "A component: typed per-entity fields." + }, + "archetype": { + "prefix": "archetype", + "body": ["archetype ${1:Name} {", "\t${2:Pos}", "}"], + "description": "An entity kind bundling a fixed set of components." + }, + "system": { + "prefix": "system", + "body": [ + "system ${1:Name} phase ${2|Start,Input,FixedUpdate,Update,LateUpdate,Render|} {", + "\t$0", + "}" + ], + "description": "A system that runs once per tick in its phase." + }, + "system with query": { + "prefix": "systemq", + "body": [ + "system ${1:Name} phase ${2|Update,FixedUpdate,LateUpdate,Render,Input|}", + " query (${3:p}) [${4:Pos}]", + "{", + "\t$0", + "}" + ], + "description": "A system whose body runs once per matching entity." + }, + "for query": { + "prefix": "forq", + "body": ["for (${1:p}) in query [${2:Pos}] {", "\t$0", "}"], + "description": "Iterate every entity matching a query." + }, + "spawn": { + "prefix": "spawn", + "body": ["spawn ${1:Kind} {", "\t${2:Pos} = { ${3:x} = ${4:0} }", "}"], + "description": "Create an entity of an archetype." + }, + "scene": { + "prefix": "scene", + "body": [ + "scene ${1:Name} {", + "\ton enter { $2 }", + "\tlayer ${3:Main} {", + "\t\t$0", + "\t}", + "}" + ], + "description": "A scene with lifecycle hooks and one layer of systems." + }, + "ui": { + "prefix": "ui", + "body": [ + "ui ${1:Name} {", + "\tpanel id=${2:Root} pad=16 gap=6 align=center {", + "\t\t$0", + "\t}", + "}" + ], + "description": "A retained UI tree." + }, + "match": { + "prefix": "match", + "body": ["match ${1:x} {", "\t${2:0} => { $3 }", "\t_ => { $0 }", "}"], + "description": "Pattern match." + }, + "machine": { + "prefix": "machine", + "body": [ + "machine reg(${1:R_PHASE}) {", + "\tstate ${2:Idle} = 0 {", + "\t\t$0", + "\t}", + "}" + ], + "description": "A state machine over a register." + }, + "extern fn": { + "prefix": "extern", + "body": ["extern fn ${1:name}(${2:a}: ${3:int}) -> ${4:int} = \"${5:c_symbol}\""], + "description": "Bind a C symbol through the FFI." + } +} diff --git a/tools/editors/vscode/src/extension.js b/tools/editors/vscode/src/extension.js new file mode 100644 index 00000000..ab816a7a --- /dev/null +++ b/tools/editors/vscode/src/extension.js @@ -0,0 +1,149 @@ +/* ============================================================================ + * The VS Code half of Ludic support. + * + * There is deliberately very little here. Highlighting comes from the TextMate + * grammar in syntaxes/ (shared, unmodified, with every other editor), and + * everything else — completion, hover, diagnostics, formatting, symbols — + * comes from `ludic-lsp`, the same binary JetBrains and Neovim talk to. This + * file's whole job is finding that binary and keeping it alive. + * ==========================================================================*/ +const path = require('path'); +const fs = require('fs'); +const os = require('os'); +const vscode = require('vscode'); +const { LanguageClient, TransportKind } = require('vscode-languageclient/node'); + +let client = null; +let output = null; + +/** Where the language server might be, in the order we should look. */ +function resolveServer(folders) { + const configured = vscode.workspace.getConfiguration('ludic').get('server.path'); + if (configured) return expand(configured); + + const names = ['ludic-lsp', 'ludic-lsp.exe']; + for (const folder of folders) { + const root = folder.uri.fsPath; + for (const rel of ['build', 'tools/build', 'bin', '.']) { + for (const name of names) { + const p = path.join(root, rel, name); + if (isExecutable(p)) return p; + } + } + } + // Fall back to PATH; spawning by bare name lets the OS resolve it. + for (const dir of (process.env.PATH || '').split(path.delimiter)) { + for (const name of names) { + const p = path.join(dir, name); + if (isExecutable(p)) return p; + } + } + return null; +} + +function resolveCompiler(folders) { + const configured = vscode.workspace.getConfiguration('ludic').get('compilerPath'); + if (configured) return expand(configured); + for (const folder of folders) { + const p = path.join(folder.uri.fsPath, 'build', 'ludicc'); + if (isExecutable(p)) return p; + } + return ''; +} + +function expand(p) { + return p.startsWith('~') ? path.join(os.homedir(), p.slice(1)) : p; +} + +function isExecutable(p) { + try { + fs.accessSync(p, fs.constants.X_OK); + return fs.statSync(p).isFile(); + } catch { + return false; + } +} + +async function start(context) { + const cfg = vscode.workspace.getConfiguration('ludic'); + if (!cfg.get('server.enabled')) return; + + const folders = vscode.workspace.workspaceFolders || []; + const server = resolveServer(folders); + if (!server) { + // Not an error worth a modal: the grammar still highlights, and plenty of + // people open a .ludic file without having built the toolchain. + output.appendLine( + 'ludic-lsp not found. Build it with tools/build-tools.sh, or set "ludic.server.path". ' + + 'Syntax highlighting works without it; completion and diagnostics do not.' + ); + return; + } + output.appendLine(`starting ${server}`); + + const serverOptions = { + run: { command: server, args: ['--stdio'], transport: TransportKind.stdio }, + debug: { command: server, args: ['--stdio'], transport: TransportKind.stdio } + }; + + const clientOptions = { + // Markdown is included on purpose: ```ludic fences in a .md get the same + // diagnostics, hover and semantic highlighting as a real source file. + documentSelector: [ + { scheme: 'file', language: 'ludic' }, + { scheme: 'file', language: 'markdown' } + ], + synchronize: { + fileEvents: vscode.workspace.createFileSystemWatcher('**/*.ludic'), + configurationSection: 'ludic' + }, + outputChannel: output, + initializationOptions: { + compilerPath: resolveCompiler(folders), + compilerDiagnostics: cfg.get('compilerDiagnostics'), + indentSize: cfg.get('indentSize') + } + }; + + client = new LanguageClient('ludic', 'Ludic Language Server', serverOptions, clientOptions); + await client.start(); + context.subscriptions.push(client); +} + +async function stop() { + if (!client) return; + const c = client; + client = null; + await c.stop(); +} + +async function activate(context) { + output = vscode.window.createOutputChannel('Ludic'); + context.subscriptions.push(output); + + context.subscriptions.push( + vscode.commands.registerCommand('ludic.restartServer', async () => { + await stop(); + await start(context); + vscode.window.setStatusBarMessage('Ludic: language server restarted', 3000); + }), + vscode.commands.registerCommand('ludic.showOutput', () => output.show()) + ); + + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration(async (e) => { + if (e.affectsConfiguration('ludic.server')) { + await stop(); + await start(context); + } + }) + ); + + await start(context); +} + +function deactivate() { + return stop(); +} + +module.exports = { activate, deactivate }; diff --git a/tools/editors/vscode/syntaxes/ludic.markdown-injection.json b/tools/editors/vscode/syntaxes/ludic.markdown-injection.json new file mode 100644 index 00000000..15931c4c --- /dev/null +++ b/tools/editors/vscode/syntaxes/ludic.markdown-injection.json @@ -0,0 +1,27 @@ +{ + "scopeName": "markdown.ludic.codeblock", + "comment": "Injects Ludic highlighting into ```ludic fences in Markdown. Any TextMate-based editor (VS Code, Sublime, JetBrains' TextMate bundles, Zed) picks this up; JetBrains' native Markdown support gets the same thing for free from the registered `Ludic` language ID, and ludic-lsp will also serve semantic tokens and diagnostics for the fence bodies in a .md file.", + "injectionSelector": "L:text.html.markdown", + "patterns": [{ "include": "#ludic-code-block" }], + "repository": { + "ludic-code-block": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ludic)((\\s+|:|,|\\{|\\?)[^`~]*)?)$", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { "name": "punctuation.definition.markdown" }, + "4": { "name": "fenced_code.block.language.markdown" }, + "5": { "name": "fenced_code.block.language.attributes.markdown" } + }, + "endCaptures": { "3": { "name": "punctuation.definition.markdown" } }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.ludic", + "patterns": [{ "include": "source.ludic" }] + } + ] + } + } +} diff --git a/tools/editors/vscode/syntaxes/ludic.tmLanguage.json b/tools/editors/vscode/syntaxes/ludic.tmLanguage.json new file mode 100644 index 00000000..8b99e208 --- /dev/null +++ b/tools/editors/vscode/syntaxes/ludic.tmLanguage.json @@ -0,0 +1,241 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Ludic", + "scopeName": "source.ludic", + "fileTypes": ["ludic"], + "comment": "Static grammar for Ludic. It is the fallback: when ludic-lsp is running, its semantic tokens refine everything here with real name resolution. Generated shapes are kept in sync with tools/ludic-tools/ludic_syntax.h.", + "patterns": [ + { "include": "#comment" }, + { "include": "#declaration" }, + { "include": "#query" }, + { "include": "#string" }, + { "include": "#number" }, + { "include": "#annotation" }, + { "include": "#keyword" }, + { "include": "#widget" }, + { "include": "#builtin" }, + { "include": "#member" }, + { "include": "#call" }, + { "include": "#typename" }, + { "include": "#operator" } + ], + "repository": { + "comment": { + "match": "#.*$", + "name": "comment.line.number-sign.ludic" + }, + "string": { + "patterns": [ + { + "name": "string.quoted.double.ludic", + "begin": "\"", + "end": "\"", + "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ludic" } }, + "endCaptures": { "0": { "name": "punctuation.definition.string.end.ludic" } }, + "patterns": [{ "name": "constant.character.escape.ludic", "match": "\\\\." }] + }, + { + "name": "string.quoted.single.ludic", + "match": "'(\\\\.|[^'\\\\])'" + } + ] + }, + "number": { + "patterns": [ + { "name": "constant.numeric.hex.ludic", "match": "\\b0[xX][0-9a-fA-F]+\\b" }, + { "name": "constant.numeric.fixed.ludic", "match": "\\b[0-9]+\\.[0-9]+\\b" }, + { "name": "constant.numeric.integer.ludic", "match": "\\b[0-9]+\\b" } + ] + }, + "annotation": { + "name": "entity.name.function.decorator.ludic", + "match": "@[A-Za-z_][A-Za-z0-9_]*" + }, + "declaration": { + "patterns": [ + { + "match": "\\b(game|module)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.unit.ludic" }, + "2": { "name": "entity.name.type.unit.ludic" } + } + }, + { + "match": "\\b(component)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.component.ludic" }, + "2": { "name": "entity.name.type.component.ludic" } + } + }, + { + "match": "\\b(archetype)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.archetype.ludic" }, + "2": { "name": "entity.name.type.archetype.ludic" } + } + }, + { + "match": "\\b(scene)\\s+([A-Za-z_][A-Za-z0-9_]*)(\\s+start)?", + "captures": { + "1": { "name": "storage.type.scene.ludic" }, + "2": { "name": "entity.name.type.scene.ludic" }, + "3": { "name": "keyword.other.start.ludic" } + } + }, + { + "match": "\\b(layer|ui)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.ludic" }, + "2": { "name": "entity.name.type.ludic" } + } + }, + { + "match": "\\b(edge\\s+)?(system)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.modifier.edge.ludic" }, + "2": { "name": "storage.type.system.ludic" }, + "3": { "name": "entity.name.function.system.ludic" } + } + }, + { + "match": "\\b(export\\s+|pure\\s+)?(extern\\s+)?(fn)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.modifier.ludic" }, + "2": { "name": "storage.modifier.extern.ludic" }, + "3": { "name": "storage.type.function.ludic" }, + "4": { "name": "entity.name.function.ludic" } + } + }, + { + "match": "\\b(const|var|let)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "storage.type.ludic" }, + "2": { "name": "variable.other.definition.ludic" } + } + }, + { + "match": "\\b(state)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.state.ludic" }, + "2": { "name": "entity.name.constant.state.ludic" } + } + }, + { + "match": "\\b(import)\\s+(?=\")", + "captures": { "1": { "name": "keyword.control.import.ludic" } } + }, + { + "match": "\\b(phase)\\s+(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b", + "captures": { + "1": { "name": "keyword.other.clause.ludic" }, + "2": { "name": "constant.language.phase.ludic" } + } + }, + { + "match": "\\b(enter)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.enter.ludic" }, + "2": { "name": "entity.name.type.scene.ludic" } + } + }, + { + "match": "\\b(spawn)\\s+([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "keyword.control.spawn.ludic" }, + "2": { "name": "entity.name.type.archetype.ludic" } + } + } + ] + }, + "query": { + "comment": "Inside a query's brackets a bare word names a component and {Word} is a filter that does not bind.", + "begin": "\\b(query)\\s*(\\[)", + "beginCaptures": { + "1": { "name": "keyword.other.query.ludic" }, + "2": { "name": "punctuation.section.brackets.begin.ludic" } + }, + "end": "(\\])", + "endCaptures": { "1": { "name": "punctuation.section.brackets.end.ludic" } }, + "patterns": [ + { + "match": "(\\{)\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*(\\})", + "captures": { + "1": { "name": "punctuation.section.braces.begin.ludic" }, + "2": { "name": "entity.name.type.tag.ludic" }, + "3": { "name": "punctuation.section.braces.end.ludic" } + } + }, + { "name": "entity.name.type.component.ludic", "match": "\\b[A-Za-z_][A-Za-z0-9_]*\\b" }, + { "name": "punctuation.separator.ludic", "match": "," } + ] + }, + "keyword": { + "patterns": [ + { "name": "keyword.control.ludic", "match": "\\b(if|else|when|while|for|in|match|machine|become|enter|return|spawn|despawn|where|break|continue|new)\\b" }, + { "name": "keyword.operator.logical.ludic", "match": "\\b(and|or|not)\\b" }, + { "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|reads|writes|needs|uses|requires|ensures|invariant|effects|on)\\b" }, + { "name": "keyword.other.ludic", "match": "\\b(import|export|pure|extern|start|edge)\\b" }, + { "name": "storage.type.ludic", "match": "\\b(game|module|component|archetype|ui|scene|layer|const|var|let|fn|system|state)\\b" }, + { "name": "support.type.primitive.ludic", "match": "\\b(int|fixed|bool|entity|str|ptr|void)\\b" }, + { "name": "constant.language.boolean.ludic", "match": "\\b(true|false)\\b" }, + { "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" } + ] + }, + "widget": { + "patterns": [ + { + "comment": "widget types, recognised by the props or the child block that follow them", + "name": "support.class.widget.ludic", + "match": "\\b(panel|col|row|label|button|image|spacer)\\b(?=\\s*(\\{|[a-z][A-Za-z0-9_]*\\s*=|$))" + }, + { + "comment": "widget props are written tight (id=Root); an assignment is written x = 1", + "match": "\\b([a-z][A-Za-z0-9_]*)(=)(?!=)", + "captures": { + "1": { "name": "variable.parameter.widget.ludic" }, + "2": { "name": "keyword.operator.assignment.ludic" } + } + } + ] + }, + "builtin": { + "patterns": [ + { + "comment": "the runtime surface — every name here resolves to rt_ in runtime/native", + "name": "support.function.builtin.ludic", + "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|load_png|load_sprites|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|setreg|self|save|load|status|print_int|quit)\\b(?=\\s*\\()" + }, + { + "comment": "compiler intrinsics — these lower straight to libc or the OS", + "name": "support.function.intrinsic.ludic", + "match": "\\b(mem_alloc|mem_realloc|mem_free|mem_copy|mem_set|peek8|poke8|peek32|poke32|peekp|pokep|peekf|pokef|ptr_add|ptr_null|ptr_is_null|as_fixed|as_int|file_open|file_read|file_write|file_seek|file_tell|file_close|read_byte|write_byte|print_str|str_len|shl|shr|band|bor|bxor|bnot|os_exit|os_time|os_argc|os_arg|file_stderr|is_windowed|game_title|win_open|win_poll|win_present|win_running|win_close)\\b(?=\\s*\\()" + } + ] + }, + "member": { + "match": "(\\.)([A-Za-z_][A-Za-z0-9_]*)", + "captures": { + "1": { "name": "punctuation.accessor.ludic" }, + "2": { "name": "variable.other.property.ludic" } + } + }, + "call": { + "match": "\\b([A-Za-z_][A-Za-z0-9_]*)\\s*(?=\\()", + "name": "entity.name.function.call.ludic" + }, + "typename": { + "comment": "components, archetypes, scenes and UI handles are Capitalised by convention", + "name": "entity.name.type.ludic", + "match": "\\b[A-Z][A-Za-z0-9_]*\\b" + }, + "operator": { + "patterns": [ + { "name": "keyword.operator.arrow.ludic", "match": "->|=>" }, + { "name": "keyword.operator.range.ludic", "match": "\\.\\." }, + { "name": "keyword.operator.comparison.ludic", "match": "==|!=|<=|>=|<|>" }, + { "name": "keyword.operator.assignment.ludic", "match": "\\+=|-=|\\*=|/=|=" }, + { "name": "keyword.operator.arithmetic.ludic", "match": "[+\\-*/%]" } + ] + } + } +} diff --git a/tools/editors/zed/README.md b/tools/editors/zed/README.md new file mode 100644 index 00000000..052796fa --- /dev/null +++ b/tools/editors/zed/README.md @@ -0,0 +1,39 @@ +# Ludic for Zed + +Zed extensions want a Tree-sitter grammar for highlighting, which this toolchain +deliberately does not ship — the vocabulary lives in one C header and is exposed +through the language server's semantic tokens instead, so there is no second +grammar to keep honest. + +That is enough for Zed: point it at `ludic-lsp` and highlighting, completion, +diagnostics and formatting all arrive over LSP. + +Add to `~/.config/zed/settings.json`: + +```json +{ + "lsp": { + "ludic-lsp": { + "binary": { "path": "/path/to/gpp/build/ludic-lsp", "arguments": ["--stdio"] }, + "initialization_options": { + "compilerPath": "/path/to/gpp/build/ludicc", + "compilerDiagnostics": true, + "indentSize": 2 + } + } + }, + "file_types": { "Ludic": ["ludic"] }, + "languages": { + "Ludic": { + "language_servers": ["ludic-lsp"], + "tab_size": 2, + "hard_tabs": false, + "format_on_save": "on" + } + } +} +``` + +If you would rather have static highlighting too, the TextMate grammar in +`tools/editors/shared/ludic.tmLanguage.json` can be dropped into a Zed extension +that declares a `grammars` entry — but it is not required. diff --git a/tools/git-hooks/pre-commit b/tools/git-hooks/pre-commit new file mode 100755 index 00000000..efe6657a --- /dev/null +++ b/tools/git-hooks/pre-commit @@ -0,0 +1,29 @@ +#!/bin/sh +# Reject a commit that contains unformatted Ludic — in source or in the ```ludic +# fences of a Markdown file. +# +# ln -sf ../../tools/git-hooks/pre-commit .git/hooks/pre-commit +# +# Checks only the files being committed, so it stays fast on a big tree. +set -e +ROOT=$(git rev-parse --show-toplevel) +FMT="$ROOT/build/ludic-fmt" + +[ -x "$FMT" ] || exit 0 # toolchain not built: do not block the commit + +FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(ludic|md|markdown)$' || true) +[ -z "$FILES" ] && exit 0 + +UNFORMATTED="" +for f in $FILES; do + [ -f "$ROOT/$f" ] || continue + "$FMT" --check -q "$ROOT/$f" >/dev/null 2>&1 || UNFORMATTED="$UNFORMATTED $f" +done + +if [ -n "$UNFORMATTED" ]; then + echo "unformatted Ludic:" + for f in $UNFORMATTED; do echo " $f"; done + echo + echo "fix with: build/ludic-fmt -w$UNFORMATTED" + exit 1 +fi diff --git a/tools/ludic-tools/ludic_fmt.h b/tools/ludic-tools/ludic_fmt.h new file mode 100644 index 00000000..89bc12af --- /dev/null +++ b/tools/ludic-tools/ludic_fmt.h @@ -0,0 +1,339 @@ +/* ============================================================================ + * ludic_fmt.h — the canonical Ludic formatter. + * + * This is deliberately NOT `ludicc --fmt`. The compiler's printer walks the AST + * after import splicing, so it drops every comment and inlines every imported + * file into whichever file you pointed it at — fine for inspecting what the + * compiler saw, catastrophic as an editor's "format on save". + * + * This formatter works on the token stream instead: + * - comments and blank lines survive, because they are tokens; + * - nothing is ever dropped or reordered, because every token is re-emitted + * in order — the only freedom taken is the whitespace between them; + * - lines are re-indented and respaced but never joined or split, so the + * author keeps control of line structure and a format-on-save never + * rewrites a file out from under someone mid-edit. + * ==========================================================================*/ +#ifndef LUDIC_FMT_H +#define LUDIC_FMT_H + +#include "ludic_syntax.h" + +typedef struct { char* b; size_t n, cap; } FSB; +static void fsb_ensure(FSB* s, size_t add){ + if (s->n + add + 1 > s->cap){ s->cap = (s->n + add + 1) * 2; s->b = realloc(s->b, s->cap); } +} +static void fsb_add(FSB* s, const char* z, size_t l){ fsb_ensure(s, l); memcpy(s->b + s->n, z, l); s->n += l; s->b[s->n] = 0; } +static void fsb_puts(FSB* s, const char* z){ fsb_add(s, z, strlen(z)); } +static void fsb_putc(FSB* s, char c){ fsb_add(s, &c, 1); } +static void fsb_indent(FSB* s, int n){ for (int i = 0; i < n; i++) fsb_putc(s, ' '); } + +/* Can this token be one side of a member access? */ +static int lud_name_like(int kind){ + return kind == LT_ID || kind == LT_KW || kind == LT_TYPE || kind == LT_PHASE || kind == LT_BOOL; +} +/* A '.' hugs an operand, a closing bracket, and another dot — the last so that + * a run of dots stays a run of dots instead of being spaced into pieces. */ +static int lud_dot_tight(const LLex* L, const LTok* t){ + if (lud_name_like(t->kind)) return 1; + if (t->kind != LT_OP) return 0; + int n = ltok_len(t); + char c0 = L->src[t->start]; + if (n == 1 && (c0 == ')' || c0 == ']' || c0 == '.')) return 1; + if (n == 2 && c0 == '.' && L->src[t->start + 1] == '.') return 1; + return 0; +} + +/* Is the token at index i a unary '-' / '!' rather than a binary operator? + * Unary iff nothing that can end an operand precedes it. */ +static int fmt_is_unary(const LLex* L, int i){ + const LTok* t = &L->v[i]; + if (t->kind != LT_OP) return 0; + int n = ltok_len(t); + if (!(n == 1 && (L->src[t->start] == '-' || L->src[t->start] == '!'))) return 0; + int p = ltok_prev_sig(L, i); + if (p < 0) return 1; + const LTok* pt = &L->v[p]; + switch (pt->kind){ + case LT_ID: case LT_INT: case LT_FLOAT: case LT_STR: case LT_CHAR: + case LT_BOOL: case LT_TYPE: case LT_PHASE: + return 0; + case LT_OP: { + char c = L->src[pt->start]; + /* a closing bracket ends an operand; every other operator does not */ + return !(ltok_len(pt) == 1 && (c == ')' || c == ']' || c == '}')); + } + default: return 1; /* keyword, annotation, comment: operand starts here */ + } +} + +/* Whitespace between the previous emitted token (prev) and the current one. */ +static int fmt_space_before(const LLex* L, int prev, int cur){ + if (prev < 0) return 0; + const LTok* p = &L->v[prev]; + const LTok* c = &L->v[cur]; + const char* src = L->src; + int plen = ltok_len(p), clen = ltok_len(c); + char p0 = src[p->start], c0 = src[c->start]; + int p1 = (plen == 1), c1 = (clen == 1); + + /* An error token is bytes we did not understand. Whatever spacing it had + * is the only spacing we can justify, so it is preserved verbatim. */ + if (p->kind == LT_ERR || c->kind == LT_ERR) return c->start - p->end; + + /* nothing hugs a closer, a separator or a member dot from the left */ + if (c1 && (c0 == ')' || c0 == ']' || c0 == ',' || c0 == ':' || c0 == ';')) return 0; + /* `.` binds tight only when it really is member access — `a.b`. A lone dot + * next to a brace is something else (or a typo) and gets normal spacing. */ + if (c1 && c0 == '.' && c->kind == LT_OP && lud_dot_tight(L, p)) return 0; + if (p1 && p0 == '.' && p->kind == LT_OP && lud_dot_tight(L, c)) return 0; + /* nothing hugs an opener from the right */ + if (p1 && (p0 == '(' || p0 == '[') && p->kind == LT_OP) return 0; + /* a unary sign binds to its operand */ + if (p->kind == LT_OP && fmt_is_unary(L, prev)) return 0; + /* @anno(args) */ + if (p->kind == LT_ANNO && c1 && c0 == '(') return 0; + + if (c1 && c0 == '(' && c->kind == LT_OP){ + /* `fn move(` and `clear(` hug; `if (`, `return (`, `x * (` do not */ + switch (p->kind){ + case LT_ID: case LT_TYPE: case LT_PHASE: return 0; + case LT_OP: return !(p1 && (p0 == ')' || p0 == ']')); + default: return 1; + } + } + return 1; +} + +/* Clause keywords hang under the declaration they qualify: a system's + * `phase`/`query` lines and a function's contract lines are indented one level + * past the `system`/`fn` they belong to, with the body brace back at the + * declaration's own level. Every example in the tree is written that way. */ +static int fmt_is_clause_word(const LLex* L, int i){ + static const char* CLAUSES[] = { "phase","query","reads","writes","needs","uses", + "requires","ensures","invariant","effects", 0 }; + if (i < 0 || i >= L->n || L->v[i].kind != LT_KW) return 0; + char b[32]; ltok_text(L, i, b, sizeof(b)); + return lud_in(CLAUSES, b); +} + +/* One pass over the token stream, re-emitting it with canonical whitespace. + * + * Two carve-outs keep the result idiomatic rather than merely uniform: + * - a run of two or more spaces is preserved verbatim, so hand-aligned + * columns (`const R_DIR: int = 0`) and deliberately set-off trailing + * comments survive a format-on-save; + * - `id=Root` inside a `ui` block and `{Enemy}` inside a query stay tight, + * because those are the spellings the language documents and uses. + */ +static char* ludic_format(const char* src, int indent_width){ + LLex L; lud_lex(&L, src); + FSB o = {0}; + /* One entry per open brace, holding the indent level to return to. Every + * brace opened on the same line shares that line's level, so a line like + * `if a { if b { if c {` steps in by ONE level, not three — and the line + * that closes them all lands back where it started. */ + int stack[512]; int hang[512]; int sp = 0; + int cur = 0; + int open = 0; /* unclosed ( or [ : the author owns the alignment */ + int brack = 0; /* unclosed [ only: query-term context */ + int ui_depth = -1; /* brace depth just outside the innermost `ui` block */ + int pending_blank = 0; + int wrote_any = 0; + int prev_line_had_comment = 0; + + int i = 0; + while (i < L.n && L.v[i].kind != LT_EOF){ + int a = i; + while (i < L.n && L.v[i].kind != LT_NL && L.v[i].kind != LT_EOF) i++; + int b = i; /* [a,b) are this line's tokens */ + if (i < L.n && L.v[i].kind == LT_NL) i++; + + if (a == b){ /* a blank line */ + if (wrote_any) pending_blank = 1; + continue; + } + + /* ---- where does this line start? --------------------------------- */ + int line_level = cur; + { /* leading closers belong to the level of the line that opened them */ + int tsp = sp, t = a; + while (t < b && L.v[t].kind == LT_OP && ltok_len(&L.v[t]) == 1 && src[L.v[t].start] == '}'){ + if (tsp > 0) line_level = stack[--tsp]; + t++; + } + } + /* Original column of this line, for the cases where the author's + * alignment is the only sensible answer. */ + int orig_ind = 0; + for (int k = L.linestart[L.v[a].line]; k < L.v[a].start; k++) orig_ind += (src[k] == '\t') ? 4 : 1; + + /* A comment on its own line, indented past its block and following a + * line that itself ended in a comment, is the continuation of that + * comment — a column the author chose, not stray indentation. */ + int comment_run = (L.v[a].kind == LT_COMMENT && b == a + 1 && prev_line_had_comment); + + int ind; + if (open > 0 || (sp > 0 && hang[sp - 1])){ + /* Inside an unclosed call, query, or a brace that was opened with + * content trailing it, the author is aligning to a column the + * formatter cannot see. Leave those lines exactly as written. */ + int ls = L.linestart[L.v[a].line]; + ind = 0; + for (int k = ls; k < L.v[a].start; k++) ind += (src[k] == '\t') ? 4 : 1; + } else { + ind = line_level * indent_width + (fmt_is_clause_word(&L, a) ? indent_width : 0); + if (comment_run && orig_ind > ind) ind = orig_ind; + } + + if (pending_blank && wrote_any) fsb_putc(&o, '\n'); + pending_blank = 0; + fsb_indent(&o, ind); + + /* ---- the tokens --------------------------------------------------- */ + int prev = -1; + int line_brack = brack, line_ui_open = (ui_depth >= 0 && sp > ui_depth); + for (int t = a; t < b; t++){ + const LTok* tk = &L.v[t]; + int gap = (prev >= 0) ? tk->start - L.v[prev].end : 0; + int want; + + if (tk->kind == LT_COMMENT){ + want = (prev >= 0) ? 2 : 0; /* set a trailing comment off */ + } else { + want = fmt_space_before(&L, prev, t); + /* a query's {Tag} filter is one word, not a record literal */ + if (line_brack > 0){ + if (tk->kind == LT_OP && ltok_len(tk) == 1 && src[tk->start] == '}') want = 0; + if (prev >= 0 && L.v[prev].kind == LT_OP && ltok_len(&L.v[prev]) == 1 && src[L.v[prev].start] == '{') want = 0; + } + /* widget props are written k=v */ + if (line_ui_open){ + int eq_here = tk->kind == LT_OP && ltok_len(tk) == 1 && src[tk->start] == '='; + int eq_prev = prev >= 0 && L.v[prev].kind == LT_OP && + ltok_len(&L.v[prev]) == 1 && src[L.v[prev].start] == '='; + if (eq_here || eq_prev) want = 0; + } + } + /* hand alignment wins over the canonical single space */ + if (gap >= 2 && want >= 1){ if (gap > 60) gap = 60; want = gap; } + if (want < 0) want = 0; + for (int k = 0; k < want; k++) fsb_putc(&o, ' '); + fsb_add(&o, src + tk->start, ltok_len(tk)); + prev = t; + + if (tk->kind == LT_OP && ltok_len(tk) == 1){ + char c = src[tk->start]; + if (c == '[') line_brack++; + else if (c == ']'){ line_brack--; if (line_brack < 0) line_brack = 0; } + } + } + fsb_putc(&o, '\n'); + wrote_any = 1; + prev_line_had_comment = (prev >= 0 && L.v[prev].kind == LT_COMMENT); + + /* ---- carry the nesting into the next line ------------------------- */ + if (ltok_is(&L, a, "ui") && L.v[a].kind == LT_KW && ui_depth < 0) ui_depth = sp; + { + int level = cur; + for (int t = a; t < b; t++){ + const LTok* tk = &L.v[t]; + if (tk->kind != LT_OP || ltok_len(tk) != 1) continue; + char c = src[tk->start]; + if (c == '{'){ + if (sp < 512){ + int nxt = ltok_next_sig(&L, t); + stack[sp] = line_level; + hang[sp] = (nxt >= 0 && nxt < b); /* content follows on this line */ + sp++; + } + level = line_level + 1; + } + else if (c == '}'){ if (sp > 0) level = stack[--sp]; } + else if (c == '(' || c == '['){ open++; if (c == '[') brack++; } + else if (c == ')' || c == ']'){ open--; if (open < 0) open = 0; if (c == ']'){ brack--; if (brack < 0) brack = 0; } } + } + cur = level; + } + if (ui_depth >= 0 && sp <= ui_depth) ui_depth = -1; + } + lud_lex_free(&L); + if (!o.b) { o.b = malloc(1); o.b[0] = 0; } + return o.b; +} + +/* ---------- markdown ------------------------------------------------------ + * Fenced Ludic in prose is still Ludic. This rewrites the body of every + * ```ludic fence in a Markdown document and leaves the prose untouched, so + * LANGUAGE.md and README.md can be kept honest by the same formatter as the + * source tree. Fence indentation (a fence inside a list item) is preserved. */ +static int md_fence_at(const char* s, int i, int* fence_len, int* info_at, char* marker){ + int j = i, n = 0; + while (s[j] == ' ') j++; /* leading indent */ + char m = s[j]; + if (m != '`' && m != '~') return 0; + while (s[j] == m){ j++; n++; } + if (n < 3) return 0; + *fence_len = n; *info_at = j; *marker = m; + return 1; +} +static int md_info_is_ludic(const char* s, int at){ + while (s[at] == ' ' || s[at] == '\t') at++; + if (strncasecmp(s + at, "ludic", 5)) return 0; + char after = s[at + 5]; + return after == 0 || after == '\n' || after == ' ' || after == '\t' || after == '\r'; +} +static char* ludic_format_markdown(const char* src, int indent_width){ + FSB o = {0}; + int i = 0; + while (src[i]){ + int ls = i; /* line start */ + int le = ls; while (src[le] && src[le] != '\n') le++; + int flen, info, indent = 0; char marker; + while (src[ls + indent] == ' ') indent++; + if (md_fence_at(src, ls, &flen, &info, &marker) && md_info_is_ludic(src, info)){ + /* copy the opening fence line verbatim */ + fsb_add(&o, src + ls, le - ls + (src[le] ? 1 : 0)); + i = src[le] ? le + 1 : le; + /* gather the body up to the closing fence */ + int bs = i; + int be = bs; + for (;;){ + if (!src[be]) break; + int ps = be, pe = ps; while (src[pe] && src[pe] != '\n') pe++; + int clen, cinfo; char cmark; + if (md_fence_at(src, ps, &clen, &cinfo, &cmark) && cmark == marker && clen >= flen){ + int only = 1; + for (int k = cinfo; k < pe; k++) if (src[k] != ' ' && src[k] != '\r'){ only = 0; break; } + if (only) break; + } + be = src[pe] ? pe + 1 : pe; + } + /* de-indent the body, format it, re-indent it */ + FSB body = {0}; + for (int p = bs; p < be; ){ + int q = p; while (src[q] && src[q] != '\n') q++; + int skip = 0; while (skip < indent && p + skip < q && src[p + skip] == ' ') skip++; + fsb_add(&body, src + p + skip, q - (p + skip)); + fsb_putc(&body, '\n'); + p = src[q] ? q + 1 : q; + } + char* f = ludic_format(body.b ? body.b : "", indent_width); + for (char* p = f; *p; ){ + char* q = strchr(p, '\n'); if (!q) q = p + strlen(p); + if (q > p) fsb_indent(&o, indent); + fsb_add(&o, p, q - p); + fsb_putc(&o, '\n'); + p = *q ? q + 1 : q; + } + free(f); free(body.b); + i = be; + continue; + } + fsb_add(&o, src + ls, le - ls + (src[le] ? 1 : 0)); + i = src[le] ? le + 1 : le; + } + if (!o.b){ o.b = malloc(1); o.b[0] = 0; } + return o.b; +} +#endif /* LUDIC_FMT_H */ diff --git a/tools/ludic-tools/ludic_fmt_main.c b/tools/ludic-tools/ludic_fmt_main.c new file mode 100644 index 00000000..95376bb3 --- /dev/null +++ b/tools/ludic-tools/ludic_fmt_main.c @@ -0,0 +1,118 @@ +/* ============================================================================ + * ludic-fmt — the Ludic formatter, as a plain CLI. + * + * Editors call this through the language server, but CI and pre-commit hooks + * want a binary they can run: + * + * ludic-fmt a.ludic b.ludic print the formatted text + * ludic-fmt -w examples rewrite every .ludic under examples/ + * ludic-fmt --check . exit 1 if anything is unformatted + * ludic-fmt LANGUAGE.md -w reformat the ```ludic fences in a document + * cat x.ludic | ludic-fmt - filter mode, for editors without LSP + * ==========================================================================*/ +#include "ludic_fmt.h" +#include +#include +#include + +static int g_write = 0, g_check = 0, g_indent = 2, g_quiet = 0; +static int g_changed = 0, g_failed = 0; + +static char* slurp(FILE* f){ + FSB s = {0}; + char buf[65536]; size_t n; + while ((n = fread(buf, 1, sizeof(buf), f)) > 0) fsb_add(&s, buf, n); + if (!s.b){ s.b = malloc(1); s.b[0] = 0; } + return s.b; +} +static int is_md(const char* p){ + size_t n = strlen(p); + return (n > 3 && !strcmp(p + n - 3, ".md")) || (n > 9 && !strcmp(p + n - 9, ".markdown")); +} +static int is_ludic(const char* p){ + size_t n = strlen(p); + return n > 6 && !strcmp(p + n - 6, ".ludic"); +} + +static void do_file(const char* path){ + FILE* f = fopen(path, "rb"); + if (!f){ fprintf(stderr, "ludic-fmt: cannot open %s\n", path); g_failed = 1; return; } + char* src = slurp(f); fclose(f); + char* out = is_md(path) ? ludic_format_markdown(src, g_indent) : ludic_format(src, g_indent); + int same = !strcmp(src, out); + if (g_check){ + if (!same){ g_changed = 1; if (!g_quiet) printf("%s\n", path); } + } else if (g_write){ + if (!same){ + FILE* w = fopen(path, "wb"); + if (!w){ fprintf(stderr, "ludic-fmt: cannot write %s\n", path); g_failed = 1; } + else { fwrite(out, 1, strlen(out), w); fclose(w); if (!g_quiet) fprintf(stderr, "formatted %s\n", path); } + g_changed = 1; + } + } else { + fwrite(out, 1, strlen(out), stdout); + } + free(src); free(out); +} +static void do_dir(const char* dir, int depth){ + if (depth > 16) return; + DIR* d = opendir(dir); + if (!d){ fprintf(stderr, "ludic-fmt: cannot open %s\n", dir); g_failed = 1; return; } + struct dirent* e; + while ((e = readdir(d))){ + if (e->d_name[0] == '.') continue; + if (!strcmp(e->d_name, "build") || !strcmp(e->d_name, "node_modules")) continue; + char p[PATH_MAX]; snprintf(p, sizeof(p), "%s/%s", dir, e->d_name); + struct stat st; if (stat(p, &st)) continue; + if (S_ISDIR(st.st_mode)) do_dir(p, depth + 1); + else if (is_ludic(p)) do_file(p); + } + closedir(d); +} + +static const char* USAGE = +"ludic-fmt — format Ludic source\n" +"\n" +"usage: ludic-fmt [options] [file|dir ...]\n" +" ludic-fmt - read stdin, write stdout\n" +"\n" +"options:\n" +" -w, --write rewrite files in place\n" +" --check list unformatted files; exit 1 if any (implies no output)\n" +" --indent N spaces per level (default 2)\n" +" -q, --quiet no per-file chatter\n" +" -h, --help this text\n" +"\n" +"Directories are walked for *.ludic. A .md/.markdown file has the body of every\n" +"```ludic fence formatted and the prose left alone.\n"; + +int main(int argc, char** argv){ + const char* files[4096]; int nf = 0; + for (int i = 1; i < argc; i++){ + const char* a = argv[i]; + if (!strcmp(a, "-w") || !strcmp(a, "--write")) g_write = 1; + else if (!strcmp(a, "--check") || !strcmp(a, "-l")) g_check = 1; + else if (!strcmp(a, "-q") || !strcmp(a, "--quiet")) g_quiet = 1; + else if (!strcmp(a, "--indent") && i + 1 < argc) g_indent = atoi(argv[++i]); + else if (!strcmp(a, "-h") || !strcmp(a, "--help")){ fputs(USAGE, stdout); return 0; } + else if (a[0] == '-' && a[1] && strcmp(a, "-")){ fprintf(stderr, "ludic-fmt: unknown option %s\n", a); return 2; } + else if (nf < 4096) files[nf++] = a; + } + if (g_indent < 1 || g_indent > 8) g_indent = 2; + + if (nf == 0 || (nf == 1 && !strcmp(files[0], "-"))){ + char* src = slurp(stdin); + char* out = ludic_format(src, g_indent); + fwrite(out, 1, strlen(out), stdout); + free(src); free(out); + return 0; + } + for (int i = 0; i < nf; i++){ + struct stat st; + if (stat(files[i], &st)){ fprintf(stderr, "ludic-fmt: no such file %s\n", files[i]); g_failed = 1; continue; } + if (S_ISDIR(st.st_mode)) do_dir(files[i], 0); + else do_file(files[i]); + } + if (g_failed) return 2; + return (g_check && g_changed) ? 1 : 0; +} diff --git a/tools/ludic-tools/ludic_index.h b/tools/ludic-tools/ludic_index.h new file mode 100644 index 00000000..216e5aff --- /dev/null +++ b/tools/ludic-tools/ludic_index.h @@ -0,0 +1,672 @@ +/* ============================================================================ + * ludic_index.h — an error-tolerant model of a Ludic workspace. + * + * The compiler's parser is the wrong tool for an editor: it stops at the first + * error and it splices imports into one flat program. A language server needs + * the opposite — keep going after a syntax error (a file being typed into is + * broken most of the time), keep every file separate, and remember where each + * name came from so it can be jumped to, renamed and completed. + * + * So this is a second, deliberately shallow reader of the same grammar. It + * recognises declarations and bindings and records their spans; it does not + * type-check. Ground-truth errors still come from `ludicc` itself (see + * ludic_lsp.c) — this layer supplies structure, not judgement. + * ==========================================================================*/ +#ifndef LUDIC_INDEX_H +#define LUDIC_INDEX_H + +#include "ludic_syntax.h" +#include + +/* ---------- symbol kinds --------------------------------------------------*/ +enum { + LS_UNIT, LS_COMPONENT, LS_FIELD, LS_ARCHETYPE, LS_CONST, LS_VAR, + LS_FN, LS_PARAM, LS_EXTERN, LS_SYSTEM, LS_UI, LS_WIDGET, LS_SCENE, + LS_LAYER, LS_LOCAL, LS_QUERYVAR, LS_STATE, LS_IMPORT +}; + +/* semantic classes, one per token — the source for semantic highlighting */ +enum { + SC_NONE, SC_KEYWORD, SC_TYPE, SC_COMPONENT, SC_ARCHETYPE, SC_SCENE, + SC_LAYER, SC_UI, SC_WIDGET, SC_PROP, SC_FIELD, SC_SYSTEM, SC_FUNCTION, + SC_BUILTIN, SC_PARAM, SC_VARIABLE, SC_CONST, SC_MODVAR, SC_PHASE, + SC_NUMBER, SC_STRING, SC_COMMENT, SC_OPERATOR, SC_ANNOTATION, SC_UNKNOWN +}; + +typedef struct { + int kind; + char name[96]; + char type[96]; /* declared type; for a query var, its component */ + char detail[224]; /* one-line signature, shown in hover and outlines */ + char doc[640]; /* the comment block sitting directly above */ + int tok; /* token index of the NAME */ + int start, end; /* byte span of the name */ + int body_start, body_end; /* span the symbol governs (a block, or the + * whole file for a top-level declaration) */ + int parent; /* enclosing symbol index, -1 at the top level */ + int exported; +} LSym; + +typedef struct { + int line, col, endline, endcol, severity; /* 1 = error, 2 = warning */ + char msg[512]; + char path[1024]; /* empty = this document */ +} LDiag; + +typedef struct LDoc { + char* path; /* filesystem path */ + char* uri; /* file:// URI */ + char* raw; /* the buffer exactly as the editor has it */ + char* text; /* what the lexer sees: `raw`, or — for Markdown — a + * copy with every byte outside a ```ludic fence blanked + * out, so offsets still line up with the real file */ + int version; + int open; /* the editor holds it (so `text` beats the disk) */ + int is_markdown; /* a .md file: only its ```ludic fences are Ludic */ + LLex lex; + int* match; /* per token: matching brace/bracket token, else -1 */ + unsigned char* cls; /* per token: semantic class */ + LSym* sym; int nsym, symcap; + char** imports; int nimport; + int had_diags; /* we published a non-empty list for it last time */ + int is_unit; /* declares `game` or `module` */ + int is_module; + char unit[96]; +} LDoc; + +typedef struct { + LDoc** d; int n, cap; + char* root; /* workspace root directory */ +} LIndex; + +/* ---------- small helpers -------------------------------------------------*/ +static void lsym_reserve(LDoc* D){ + if (D->nsym >= D->symcap){ D->symcap = D->symcap ? D->symcap * 2 : 128; D->sym = realloc(D->sym, D->symcap * sizeof(LSym)); } +} +static void lcpy(char* dst, int cap, const char* s, int n){ + if (n >= cap) n = cap - 1; if (n < 0) n = 0; + memcpy(dst, s, n); dst[n] = 0; +} +static void lcatf(char* dst, int cap, const char* fmt, ...){ + int used = (int)strlen(dst); if (used >= cap - 1) return; + va_list ap; va_start(ap, fmt); vsnprintf(dst + used, cap - used, fmt, ap); va_end(ap); +} + +/* ---------- positions ----------------------------------------------------- + * LSP counts characters in UTF-16 code units by default. Ludic source is UTF-8 + * and string literals really do carry non-ASCII (the language ships a Unicode + * TrueType path), so the conversion is not optional. */ +static int lutf16_len(const char* s, int nbytes){ + int u = 0; + for (int i = 0; i < nbytes; ){ + unsigned char c = (unsigned char)s[i]; + if (c < 0x80){ i += 1; u += 1; } + else if (c < 0xE0){ i += 2; u += 1; } + else if (c < 0xF0){ i += 3; u += 1; } + else { i += 4; u += 2; } /* astral planes are a surrogate pair */ + } + return u; +} +static int ldoc_line_of(const LDoc* D, int off){ + int lo = 0, hi = D->lex.nline - 1; + while (lo < hi){ int mid = (lo + hi + 1) / 2; if (D->lex.linestart[mid] <= off) lo = mid; else hi = mid - 1; } + return lo; +} +static int ldoc_col_of(const LDoc* D, int off){ + int line = ldoc_line_of(D, off); + return lutf16_len(D->text + D->lex.linestart[line], off - D->lex.linestart[line]); +} +static int ldoc_offset_of(const LDoc* D, int line, int character){ + if (line < 0) return 0; + if (line >= D->lex.nline) return (int)strlen(D->text); + int off = D->lex.linestart[line]; + int end = (line + 1 < D->lex.nline) ? D->lex.linestart[line + 1] : (int)strlen(D->text); + int u = 0; + while (off < end && u < character){ + unsigned char c = (unsigned char)D->text[off]; + if (c < 0x80){ off += 1; u += 1; } + else if (c < 0xE0){ off += 2; u += 1; } + else if (c < 0xF0){ off += 3; u += 1; } + else { off += 4; u += 2; } + } + return off; +} +/* The token the cursor is on. A caret sitting exactly between two tokens + * belongs to the one it is *inside*; only when it is inside none of them does + * the token ending there win — otherwise `st.|guard` resolves to the dot. */ +static int ldoc_tok_at(const LDoc* D, int off){ + int touching = -1; + for (int i = 0; i < D->lex.n; i++){ + const LTok* t = &D->lex.v[i]; + if (t->kind == LT_NL || t->kind == LT_EOF) continue; + if (off >= t->start && off < t->end) return i; + if (off == t->end && touching < 0) touching = i; + if (t->start > off) break; + } + return touching; +} + +/* ---------- brace matching ------------------------------------------------*/ +static void ldoc_match_braces(LDoc* D){ + free(D->match); + D->match = malloc(sizeof(int) * (D->lex.n + 1)); + for (int i = 0; i < D->lex.n; i++) D->match[i] = -1; + int stack[512], top = 0; + for (int i = 0; i < D->lex.n; i++){ + const LTok* t = &D->lex.v[i]; + if (t->kind != LT_OP || ltok_len(t) != 1) continue; + char c = D->text[t->start]; + if (c == '{' || c == '(' || c == '['){ if (top < 512) stack[top++] = i; } + else if (c == '}' || c == ')' || c == ']'){ + if (top > 0){ int o = stack[--top]; D->match[o] = i; D->match[i] = o; } + } + } +} + +/* ---------- doc comments -------------------------------------------------- + * The comment block immediately above a declaration is its documentation — + * the convention the runtime and examples already follow. */ +static void ldoc_collect_doc(LDoc* D, int decl_tok, char* out, int cap){ + out[0] = 0; + int line = D->lex.v[decl_tok].line; + /* walk backwards over comment-only lines */ + int first = -1; + for (int i = decl_tok - 1; i >= 0; i--){ + const LTok* t = &D->lex.v[i]; + if (t->kind == LT_NL) continue; + if (t->kind != LT_COMMENT) break; + if (t->line >= line) break; /* trailing, not leading */ + /* the comment must own its line */ + int p = ltok_prev_sig(&D->lex, i); + if (p >= 0 && D->lex.v[p].line == t->line) break; + if (t->line < line - 1 && first >= 0) break;/* a blank line ends it */ + if (first >= 0 && D->lex.v[first].line != t->line + 1) break; + first = i; line = t->line; + } + if (first < 0) return; + for (int i = first; i < decl_tok; i++){ + const LTok* t = &D->lex.v[i]; + if (t->kind != LT_COMMENT) continue; + int s = t->start + 1; /* skip '#' */ + while (s < t->end && (D->text[s] == ' ' || D->text[s] == '\t' || D->text[s] == '#' || D->text[s] == '*')) s++; + int used = (int)strlen(out); + int n = t->end - s; + if (used + n + 2 >= cap) break; + memcpy(out + used, D->text + s, n); out[used + n] = '\n'; out[used + n + 1] = 0; + } +} + +/* ---------- the shallow parser -------------------------------------------*/ +typedef struct { LDoc* D; int i; } LP; + +static int lp_kind(LP* p){ return p->i < p->D->lex.n ? p->D->lex.v[p->i].kind : LT_EOF; } +static int lp_is(LP* p, const char* s){ return ltok_is(&p->D->lex, p->i, s); } +static void lp_skipnl(LP* p){ while (p->i < p->D->lex.n && (lp_kind(p) == LT_NL || lp_kind(p) == LT_COMMENT)) p->i++; } +static void lp_adv(LP* p){ if (p->i < p->D->lex.n) p->i++; lp_skipnl(p); } +static char* lp_word(LP* p, char* buf, int cap){ + buf[0] = 0; + if (p->i < p->D->lex.n) lcpy(buf, cap, p->D->text + p->D->lex.v[p->i].start, ltok_len(&p->D->lex.v[p->i])); + return buf; +} +/* Consume an identifier-ish token, returning its index (or -1). */ +static int lp_name(LP* p){ + int k = lp_kind(p); + if (k == LT_ID || k == LT_TYPE || k == LT_PHASE || k == LT_KW || k == LT_BOOL){ int t = p->i; lp_adv(p); return t; } + return -1; +} +static int lsym_add(LDoc* D, int kind, int nametok, int parent){ + lsym_reserve(D); + LSym* s = &D->sym[D->nsym]; + memset(s, 0, sizeof(*s)); + s->kind = kind; s->tok = nametok; s->parent = parent; + if (nametok >= 0){ + const LTok* t = &D->lex.v[nametok]; + s->start = t->start; s->end = t->end; + lcpy(s->name, sizeof(s->name), D->text + t->start, ltok_len(t)); + } + s->body_start = 0; s->body_end = (int)strlen(D->text); + return D->nsym++; +} +/* Skip a balanced group starting at the current opener; leaves p after it. */ +static void lp_skip_group(LP* p){ + int m = (p->i < p->D->lex.n) ? p->D->match[p->i] : -1; + if (m < 0){ lp_adv(p); return; } + p->i = m + 1; lp_skipnl(p); +} +/* Read `name: Type` pairs inside the parentheses at p->i, recording params. */ +static void lp_params(LP* p, int owner, int kind, char* sig, int sigcap){ + if (!lp_is(p, "(")) return; + int close = p->D->match[p->i]; + lcatf(sig, sigcap, "("); + lp_adv(p); + int first = 1; + while (p->i < p->D->lex.n && (close < 0 || p->i < close)){ + if (lp_is(p, ")")) break; + if (lp_is(p, ",")){ lp_adv(p); continue; } + int nt = lp_name(p); if (nt < 0){ lp_adv(p); continue; } + char ty[96]; ty[0] = 0; + if (lp_is(p, ":")){ lp_adv(p); int tt = lp_name(p); if (tt >= 0) lcpy(ty, sizeof(ty), p->D->text + p->D->lex.v[tt].start, ltok_len(&p->D->lex.v[tt])); } + int s = lsym_add(p->D, kind, nt, owner); + lcpy(p->D->sym[s].type, sizeof(p->D->sym[s].type), ty, (int)strlen(ty)); + lcatf(sig, sigcap, "%s%s: %s", first ? "" : ", ", p->D->sym[s].name, ty[0] ? ty : "?"); + first = 0; + } + if (close >= 0) p->i = close + 1; + lp_skipnl(p); + lcatf(sig, sigcap, ")"); +} +/* `[Pos, Vel, {Enemy}]` — bind the listed components to the named variables in + * order, skipping {Tag} terms, which filter without binding. */ +static void lp_query_terms(LP* p, int owner, int* vars, int nvars, int scope_start, int scope_end){ + if (!lp_is(p, "[")) return; + int close = p->D->match[p->i]; + lp_adv(p); + int bind = 0; + while (p->i < p->D->lex.n && (close < 0 || p->i < close)){ + if (lp_is(p, "]")) break; + if (lp_is(p, ",")){ lp_adv(p); continue; } + if (lp_is(p, "{")){ /* a filter term */ + int cb = p->D->match[p->i]; lp_adv(p); + int nt = lp_name(p); (void)nt; + if (cb >= 0) p->i = cb + 1; else lp_adv(p); + lp_skipnl(p); continue; + } + int nt = lp_name(p); if (nt < 0){ lp_adv(p); continue; } + if (bind < nvars && vars[bind] >= 0){ + int s = lsym_add(p->D, LS_QUERYVAR, vars[bind], owner); + lcpy(p->D->sym[s].type, sizeof(p->D->sym[s].type), p->D->text + p->D->lex.v[nt].start, ltok_len(&p->D->lex.v[nt])); + p->D->sym[s].body_start = scope_start; p->D->sym[s].body_end = scope_end; + lcatf(p->D->sym[s].detail, sizeof(p->D->sym[s].detail), "%s: %s (query binding)", p->D->sym[s].name, p->D->sym[s].type); + } + bind++; + } + if (close >= 0) p->i = close + 1; + lp_skipnl(p); + if (lp_is(p, "where")) lp_adv(p); /* the condition is ordinary expression */ +} +/* `(a, b)` variable list before `in query` / after the `query` clause. */ +static int lp_varlist(LP* p, int* out, int max){ + int n = 0; + if (!lp_is(p, "(")) return 0; + int close = p->D->match[p->i]; + lp_adv(p); + while (p->i < p->D->lex.n && (close < 0 || p->i < close)){ + if (lp_is(p, ")")) break; + if (lp_is(p, ",")){ lp_adv(p); continue; } + int nt = lp_name(p); if (nt < 0){ lp_adv(p); continue; } + if (n < max) out[n++] = nt; + } + if (close >= 0) p->i = close + 1; + lp_skipnl(p); + return n; +} + +static void lp_block(LP* p, int owner, int scope_end); + +/* statements — we only care about what BINDS a name or opens a scope */ +static void lp_stmt(LP* p, int owner, int scope_end){ + LDoc* D = p->D; + if (lp_is(p, "let")){ + lp_adv(p); int nt = lp_name(p); if (nt < 0) return; + char ty[96]; ty[0] = 0; + if (lp_is(p, ":")){ lp_adv(p); int tt = lp_name(p); if (tt >= 0) lcpy(ty, sizeof(ty), D->text + D->lex.v[tt].start, ltok_len(&D->lex.v[tt])); } + int s = lsym_add(D, LS_LOCAL, nt, owner); + lcpy(D->sym[s].type, sizeof(D->sym[s].type), ty, (int)strlen(ty)); + D->sym[s].body_start = D->lex.v[nt].start; D->sym[s].body_end = scope_end; + return; + } + if (lp_is(p, "for")){ + lp_adv(p); + if (lp_is(p, "(")){ /* for (a, b) in query [...] */ + int vars[16]; int nv = lp_varlist(p, vars, 16); + if (lp_is(p, "in")) lp_adv(p); + if (lp_is(p, "query")) lp_adv(p); + int body_end = scope_end; + /* the loop body is the next {...}; bindings live there */ + lp_query_terms(p, owner, vars, nv, D->lex.v[p->i < D->lex.n ? p->i : D->lex.n - 1].start, body_end); + return; + } + int nt = lp_name(p); /* for i in a .. b */ + if (nt >= 0){ + int s = lsym_add(D, LS_LOCAL, nt, owner); + lcpy(D->sym[s].type, sizeof(D->sym[s].type), "int", 3); + D->sym[s].body_start = D->lex.v[nt].start; D->sym[s].body_end = scope_end; + } + return; + } + if (lp_is(p, "state")){ /* machine { state Idle = 0 {…} } */ + lp_adv(p); int nt = lp_name(p); + if (nt >= 0) lsym_add(D, LS_STATE, nt, owner); + return; + } + lp_adv(p); +} + +static void lp_block(LP* p, int owner, int scope_end){ + if (!lp_is(p, "{")) return; + int close = p->D->match[p->i]; + int end = close >= 0 ? p->D->lex.v[close].start : scope_end; + lp_adv(p); + while (p->i < p->D->lex.n && lp_kind(p) != LT_EOF){ + if (close >= 0 && p->i >= close) break; + if (lp_is(p, "}")) break; + if (lp_is(p, "{")){ lp_block(p, owner, end); continue; } + int before = p->i; + lp_stmt(p, owner, end); + if (p->i == before) lp_adv(p); + } + if (close >= 0) p->i = close + 1; else lp_adv(p); + lp_skipnl(p); +} + +/* `panel id=Root w=288 { … }` — each id= mints a UI_ handle. */ +static void lp_widget(LP* p, int owner, int uisym){ + LDoc* D = p->D; + int type_tok = lp_name(p); if (type_tok < 0) return; + while (p->i < D->lex.n && lp_kind(p) == LT_ID && ltok_is(&D->lex, ltok_next_sig(&D->lex, p->i) < 0 ? p->i : ltok_next_sig(&D->lex, p->i), "=")){ + int key = p->i; char kb[64]; lcpy(kb, sizeof(kb), D->text + D->lex.v[key].start, ltok_len(&D->lex.v[key])); + lp_adv(p); /* key */ + if (lp_is(p, "=")) lp_adv(p); /* '=' */ + if (!strcmp(kb, "id")){ + int nt = lp_name(p); + if (nt >= 0){ + int s = lsym_add(D, LS_WIDGET, nt, uisym); + snprintf(D->sym[s].name, sizeof(D->sym[s].name), "UI_%.*s", + ltok_len(&D->lex.v[nt]), D->text + D->lex.v[nt].start); + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "%s widget handle", + (const char*)(D->text + D->lex.v[type_tok].start)); + lcpy(D->sym[s].type, sizeof(D->sym[s].type), "int", 3); + } + } else { + /* skip one value expression: stop at the next `key=` or at a brace */ + while (p->i < D->lex.n && lp_kind(p) != LT_EOF && !lp_is(p, "{") && !lp_is(p, "}")){ + if (lp_is(p, "(") || lp_is(p, "[")){ lp_skip_group(p); continue; } + int nx = ltok_next_sig(&D->lex, p->i); + if (lp_kind(p) == LT_ID && nx >= 0 && ltok_is(&D->lex, nx, "=")) break; + lp_adv(p); + } + } + } + if (lp_is(p, "{")){ + int close = D->match[p->i]; + lp_adv(p); + while (p->i < D->lex.n && lp_kind(p) != LT_EOF && !lp_is(p, "}")){ + if (close >= 0 && p->i >= close) break; + int before = p->i; + lp_widget(p, owner, uisym); + if (p->i == before) lp_adv(p); + } + if (close >= 0) p->i = close + 1; else lp_adv(p); + lp_skipnl(p); + } +} + +/* one top-level declaration */ +static void lp_decl(LP* p, int parent){ + LDoc* D = p->D; + char w[96]; lp_word(p, w, sizeof(w)); + int decl_tok = p->i; + + if (!strcmp(w, "import")){ + lp_adv(p); + if (lp_kind(p) == LT_STR){ + const LTok* t = &D->lex.v[p->i]; + int n = ltok_len(t) - 2; if (n < 0) n = 0; + char* rel = malloc(n + 1); memcpy(rel, D->text + t->start + 1, n); rel[n] = 0; + D->imports = realloc(D->imports, (D->nimport + 1) * sizeof(char*)); + D->imports[D->nimport++] = rel; + int s = lsym_add(D, LS_IMPORT, p->i, parent); + lcpy(D->sym[s].name, sizeof(D->sym[s].name), rel, (int)strlen(rel)); + lp_adv(p); + } + return; + } + if (!strcmp(w, "component") || !strcmp(w, "archetype")){ + int is_comp = !strcmp(w, "component"); + lp_adv(p); int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, is_comp ? LS_COMPONENT : LS_ARCHETYPE, nt, parent); + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + while (lp_kind(p) == LT_ANNO) lp_adv(p); + snprintf(D->sym[s].detail, sizeof(D->sym[s].detail), "%s %s {", + is_comp ? "component" : "archetype", D->sym[s].name); + if (!lp_is(p, "{")) return; + int close = D->match[p->i]; + D->sym[s].body_start = D->lex.v[p->i].start; + D->sym[s].body_end = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + lp_adv(p); + int first = 1; + while (p->i < D->lex.n && lp_kind(p) != LT_EOF && !lp_is(p, "}")){ + if (close >= 0 && p->i >= close) break; + if (lp_is(p, ",")){ lp_adv(p); continue; } + int ft = lp_name(p); if (ft < 0){ lp_adv(p); continue; } + if (is_comp){ + int f = lsym_add(D, LS_FIELD, ft, s); + if (lp_is(p, ":")){ + lp_adv(p); int tt = lp_name(p); + if (tt >= 0) lcpy(D->sym[f].type, sizeof(D->sym[f].type), D->text + D->lex.v[tt].start, ltok_len(&D->lex.v[tt])); + } + lcatf(D->sym[f].detail, sizeof(D->sym[f].detail), "%s.%s: %s", D->sym[s].name, D->sym[f].name, D->sym[f].type); + if (lp_is(p, "=")){ lp_adv(p); while (p->i < D->lex.n && !lp_is(p, ",") && !lp_is(p, "}") && lp_kind(p) != LT_EOF){ if (lp_is(p, "(") || lp_is(p, "{") || lp_is(p, "[")) lp_skip_group(p); else lp_adv(p); } } + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "%s %s: %s", first ? "" : ",", D->sym[f].name, D->sym[f].type); + } else { + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "%s %.*s", first ? "" : ",", + ltok_len(&D->lex.v[ft]), D->text + D->lex.v[ft].start); + } + first = 0; + } + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), " }"); + if (close >= 0) p->i = close + 1; else lp_adv(p); + lp_skipnl(p); + return; + } + if (!strcmp(w, "const") || !strcmp(w, "var")){ + int kind = !strcmp(w, "const") ? LS_CONST : LS_VAR; + lp_adv(p); int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, kind, nt, parent); + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + if (lp_is(p, ":")){ lp_adv(p); int tt = lp_name(p); if (tt >= 0) lcpy(D->sym[s].type, sizeof(D->sym[s].type), D->text + D->lex.v[tt].start, ltok_len(&D->lex.v[tt])); } + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "%s %s: %s", w, D->sym[s].name, D->sym[s].type); + while (p->i < D->lex.n && lp_kind(p) != LT_NL && lp_kind(p) != LT_EOF){ + if (lp_is(p, "(") || lp_is(p, "{") || lp_is(p, "[")) lp_skip_group(p); else p->i++; + } + lp_skipnl(p); + return; + } + if (!strcmp(w, "extern")){ + lp_adv(p); if (lp_is(p, "fn")) lp_adv(p); + int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, LS_EXTERN, nt, parent); + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + char sig[224]; snprintf(sig, sizeof(sig), "extern fn %s", D->sym[s].name); + lp_params(p, s, LS_PARAM, sig, sizeof(sig)); + if (lp_is(p, "->")){ lp_adv(p); int tt = lp_name(p); if (tt >= 0){ lcpy(D->sym[s].type, sizeof(D->sym[s].type), D->text + D->lex.v[tt].start, ltok_len(&D->lex.v[tt])); lcatf(sig, sizeof(sig), " -> %s", D->sym[s].type); } } + lcpy(D->sym[s].detail, sizeof(D->sym[s].detail), sig, (int)strlen(sig)); + while (p->i < D->lex.n && lp_kind(p) != LT_NL && lp_kind(p) != LT_EOF) p->i++; + lp_skipnl(p); + return; + } + if (!strcmp(w, "fn") || !strcmp(w, "pure") || !strcmp(w, "export")){ + int exported = !strcmp(w, "export"); + if (!strcmp(w, "pure") || exported){ lp_adv(p); if (lp_is(p, "pure")) lp_adv(p); } + if (lp_is(p, "fn")) lp_adv(p); + int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, LS_FN, nt, parent); + D->sym[s].exported = exported; + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + char sig[224]; snprintf(sig, sizeof(sig), "%sfn %s", exported ? "export " : "", D->sym[s].name); + lp_params(p, s, LS_PARAM, sig, sizeof(sig)); + if (lp_is(p, "->")){ lp_adv(p); int tt = lp_name(p); if (tt >= 0) lcpy(D->sym[s].type, sizeof(D->sym[s].type), D->text + D->lex.v[tt].start, ltok_len(&D->lex.v[tt])); } + lcatf(sig, sizeof(sig), " -> %s", D->sym[s].type[0] ? D->sym[s].type : "void"); + lcpy(D->sym[s].detail, sizeof(D->sym[s].detail), sig, (int)strlen(sig)); + /* contracts sit between the signature and the body */ + while (lp_is(p, "requires") || lp_is(p, "ensures") || lp_is(p, "invariant") || lp_is(p, "effects")){ + lp_adv(p); + while (p->i < D->lex.n && lp_kind(p) != LT_NL && lp_kind(p) != LT_EOF && !lp_is(p, "{")){ + if (lp_is(p, "(") || lp_is(p, "[")) lp_skip_group(p); else p->i++; + } + lp_skipnl(p); + } + if (lp_is(p, "{")){ + int close = D->match[p->i]; + D->sym[s].body_start = D->lex.v[p->i].start; + D->sym[s].body_end = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + /* params are visible for the whole body */ + for (int q = 0; q < D->nsym; q++) if (D->sym[q].parent == s && D->sym[q].kind == LS_PARAM){ + D->sym[q].body_start = D->sym[s].body_start; D->sym[q].body_end = D->sym[s].body_end; + } + lp_block(p, s, D->sym[s].body_end); + } + return; + } + if (!strcmp(w, "system") || !strcmp(w, "edge")){ + if (!strcmp(w, "edge")){ lp_adv(p); if (!lp_is(p, "system")) return; } + lp_adv(p); + int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, LS_SYSTEM, nt, parent); + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + lcpy(D->sym[s].type, sizeof(D->sym[s].type), "Update", 6); + while (lp_kind(p) == LT_ANNO) lp_adv(p); + int vars[16]; int nv = 0; int have_query = 0; + for (;;){ + if (lp_is(p, "phase")){ lp_adv(p); int tt = lp_name(p); if (tt >= 0) lcpy(D->sym[s].type, sizeof(D->sym[s].type), D->text + D->lex.v[tt].start, ltok_len(&D->lex.v[tt])); } + else if (lp_is(p, "query")){ lp_adv(p); have_query = 1; nv = lp_varlist(p, vars, 16); break; } + else if (lp_is(p, "reads") || lp_is(p, "writes") || lp_is(p, "uses") || lp_is(p, "effects")){ lp_adv(p); if (lp_is(p, "[")) lp_skip_group(p); } + else if (lp_is(p, "needs")){ lp_adv(p); lp_name(p); if (lp_is(p, "[")) lp_skip_group(p); } + else break; + lp_skipnl(p); + } + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "system %s phase %s", D->sym[s].name, D->sym[s].type); + /* find the body first, so query bindings can be scoped to it */ + int body_open = p->i; + if (have_query){ + int save = p->i; + /* the query terms come before the body */ + int scan = p->i; + while (scan < D->lex.n && !ltok_is(&D->lex, scan, "{") && D->lex.v[scan].kind != LT_EOF) scan++; + int close = (scan < D->lex.n) ? D->match[scan] : -1; + int bs = (scan < D->lex.n) ? D->lex.v[scan].start : 0; + int be = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + p->i = save; + lp_query_terms(p, s, vars, nv, bs, be); + body_open = p->i; + } + (void)body_open; + if (lp_is(p, "{")){ + int close = D->match[p->i]; + D->sym[s].body_start = D->lex.v[p->i].start; + D->sym[s].body_end = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + lp_block(p, s, D->sym[s].body_end); + } + return; + } + if (!strcmp(w, "ui")){ + lp_adv(p); int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, LS_UI, nt, parent); + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "ui %s", D->sym[s].name); + /* the block name is a handle too */ + { int h = lsym_add(D, LS_WIDGET, nt, s); + snprintf(D->sym[h].name, sizeof(D->sym[h].name), "UI_%s", D->sym[s].name); + lcpy(D->sym[h].type, sizeof(D->sym[h].type), "int", 3); + lcatf(D->sym[h].detail, sizeof(D->sym[h].detail), "root handle of ui %s", D->sym[s].name); } + if (lp_is(p, "{")){ + int close = D->match[p->i]; + D->sym[s].body_start = D->lex.v[p->i].start; + D->sym[s].body_end = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + lp_adv(p); + while (p->i < D->lex.n && lp_kind(p) != LT_EOF && !lp_is(p, "}")){ + if (close >= 0 && p->i >= close) break; + int before = p->i; + lp_widget(p, s, s); + if (p->i == before) lp_adv(p); + } + if (close >= 0) p->i = close + 1; else lp_adv(p); + lp_skipnl(p); + } + return; + } + if (!strcmp(w, "scene")){ + lp_adv(p); int nt = lp_name(p); if (nt < 0) return; + int s = lsym_add(D, LS_SCENE, nt, parent); + ldoc_collect_doc(D, decl_tok, D->sym[s].doc, sizeof(D->sym[s].doc)); + int start = 0; + if (lp_is(p, "start")){ start = 1; lp_adv(p); } + lcatf(D->sym[s].detail, sizeof(D->sym[s].detail), "scene %s%s", D->sym[s].name, start ? " start" : ""); + if (lp_is(p, "{")){ + int close = D->match[p->i]; + D->sym[s].body_start = D->lex.v[p->i].start; + D->sym[s].body_end = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + lp_adv(p); + while (p->i < D->lex.n && lp_kind(p) != LT_EOF && !lp_is(p, "}")){ + if (close >= 0 && p->i >= close) break; + int before = p->i; + if (lp_is(p, "on")){ lp_adv(p); lp_name(p); lp_block(p, s, D->sym[s].body_end); } + else if (lp_is(p, "layer")){ + lp_adv(p); int lt = lp_name(p); + int ls = lt >= 0 ? lsym_add(D, LS_LAYER, lt, s) : -1; + if (ls >= 0) lcatf(D->sym[ls].detail, sizeof(D->sym[ls].detail), "layer %s of scene %s", D->sym[ls].name, D->sym[s].name); + if (lp_is(p, "{")){ + int lc = D->match[p->i]; + if (ls >= 0){ D->sym[ls].body_start = D->lex.v[p->i].start; D->sym[ls].body_end = lc >= 0 ? D->lex.v[lc].end : D->sym[s].body_end; } + lp_adv(p); + while (p->i < D->lex.n && lp_kind(p) != LT_EOF && !lp_is(p, "}")){ + if (lc >= 0 && p->i >= lc) break; + int b2 = p->i; lp_decl(p, ls >= 0 ? ls : s); + if (p->i == b2) lp_adv(p); + } + if (lc >= 0) p->i = lc + 1; else lp_adv(p); + lp_skipnl(p); + } + } else lp_adv(p); + if (p->i == before) lp_adv(p); + } + if (close >= 0) p->i = close + 1; else lp_adv(p); + lp_skipnl(p); + } + return; + } + lp_adv(p); +} + +static void ldoc_parse(LDoc* D){ + D->nsym = 0; + for (int i = 0; i < D->nimport; i++) free(D->imports[i]); + free(D->imports); D->imports = 0; D->nimport = 0; + D->is_unit = 0; D->is_module = 0; D->unit[0] = 0; + + LP p = { D, 0 }; + lp_skipnl(&p); + while (lp_is(&p, "import")) { lp_decl(&p, -1); lp_skipnl(&p); } + int unit_parent = -1; + if (lp_is(&p, "game") || lp_is(&p, "module")){ + D->is_module = lp_is(&p, "module"); + D->is_unit = 1; + lp_adv(&p); + int nt = lp_name(&p); + if (nt >= 0){ + unit_parent = lsym_add(D, LS_UNIT, nt, -1); + lcpy(D->unit, sizeof(D->unit), D->sym[unit_parent].name, (int)strlen(D->sym[unit_parent].name)); + lcatf(D->sym[unit_parent].detail, sizeof(D->sym[unit_parent].detail), "%s %s", D->is_module ? "module" : "game", D->unit); + } + if (lp_is(&p, "{")){ + int close = D->match[p.i]; + if (unit_parent >= 0){ + D->sym[unit_parent].body_start = D->lex.v[p.i].start; + D->sym[unit_parent].body_end = close >= 0 ? D->lex.v[close].end : (int)strlen(D->text); + } + lp_adv(&p); + while (p.i < D->lex.n && lp_kind(&p) != LT_EOF && !lp_is(&p, "}")){ + if (close >= 0 && p.i >= close) break; + int before = p.i; lp_decl(&p, unit_parent); + if (p.i == before) lp_adv(&p); + } + } + return; + } + /* A fragment: an imported file is a bare list of declarations. */ + while (p.i < D->lex.n && lp_kind(&p) != LT_EOF){ + int before = p.i; lp_decl(&p, -1); + if (p.i == before) lp_adv(&p); + } +} +#endif /* LUDIC_INDEX_H */ diff --git a/tools/ludic-tools/ludic_json.h b/tools/ludic-tools/ludic_json.h new file mode 100644 index 00000000..0aee150a --- /dev/null +++ b/tools/ludic-tools/ludic_json.h @@ -0,0 +1,191 @@ +/* ============================================================================ + * ludic_json.h — just enough JSON for LSP, and no dependencies. + * + * The rest of this toolchain is C with no third-party libraries, and the + * language server should not be the thing that drags a package manager into a + * project whose whole premise is a self-contained native pipeline. This is a + * recursive-descent reader and an escaping writer; nothing more. + * ==========================================================================*/ +#ifndef LUDIC_JSON_H +#define LUDIC_JSON_H + +#include +#include +#include +#include +#include + +enum { JNULL, JBOOL, JNUM, JSTR, JARR, JOBJ }; + +typedef struct JVal JVal; +struct JVal { + int t; + double num; + int b; + char* s; /* JSTR: decoded UTF-8 */ + JVal** kids; char** keys; int n, cap; +}; + +static JVal* jnew(int t){ JVal* v = calloc(1, sizeof(JVal)); v->t = t; return v; } +static void jfree(JVal* v){ + if (!v) return; + for (int i = 0; i < v->n; i++){ jfree(v->kids[i]); free(v->keys ? v->keys[i] : 0); } + free(v->kids); free(v->keys); free(v->s); free(v); +} +static void jpush(JVal* v, const char* key, JVal* kid){ + if (v->n >= v->cap){ + v->cap = v->cap ? v->cap * 2 : 8; + v->kids = realloc(v->kids, v->cap * sizeof(JVal*)); + v->keys = realloc(v->keys, v->cap * sizeof(char*)); + } + v->keys[v->n] = key ? strdup(key) : 0; + v->kids[v->n++] = kid; +} + +static void jskip(const char** p){ while (**p == ' ' || **p == '\t' || **p == '\n' || **p == '\r') (*p)++; } +static JVal* jparse_at(const char** p); + +static void jutf8(char** o, unsigned cp){ + if (cp < 0x80) *(*o)++ = (char)cp; + else if (cp < 0x800){ *(*o)++ = (char)(0xC0 | (cp >> 6)); *(*o)++ = (char)(0x80 | (cp & 63)); } + else if (cp < 0x10000){ *(*o)++ = (char)(0xE0 | (cp >> 12)); *(*o)++ = (char)(0x80 | ((cp >> 6) & 63)); *(*o)++ = (char)(0x80 | (cp & 63)); } + else { *(*o)++ = (char)(0xF0 | (cp >> 18)); *(*o)++ = (char)(0x80 | ((cp >> 12) & 63)); *(*o)++ = (char)(0x80 | ((cp >> 6) & 63)); *(*o)++ = (char)(0x80 | (cp & 63)); } +} +static char* jparse_string(const char** p){ + if (**p != '"') return 0; + (*p)++; + const char* s = *p; + size_t cap = strlen(s) + 1; + char* out = malloc(cap); char* o = out; + while (**p && **p != '"'){ + if (**p == '\\'){ + (*p)++; + char c = **p; (*p)++; + switch (c){ + case 'n': *o++ = '\n'; break; + case 't': *o++ = '\t'; break; + case 'r': *o++ = '\r'; break; + case 'b': *o++ = '\b'; break; + case 'f': *o++ = '\f'; break; + case 'u': { + unsigned cp = (unsigned)strtoul((char[5]){ (*p)[0], (*p)[1], (*p)[2], (*p)[3], 0 }, 0, 16); + *p += 4; + if (cp >= 0xD800 && cp < 0xDC00 && (*p)[0] == '\\' && (*p)[1] == 'u'){ + unsigned lo = (unsigned)strtoul((char[5]){ (*p)[2], (*p)[3], (*p)[4], (*p)[5], 0 }, 0, 16); + *p += 6; + cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00); + } + jutf8(&o, cp); + break; + } + default: *o++ = c; + } + } else *o++ = *(*p)++; + } + if (**p == '"') (*p)++; + *o = 0; + return out; +} +static JVal* jparse_at(const char** p){ + jskip(p); + char c = **p; + if (c == '{'){ + (*p)++; JVal* v = jnew(JOBJ); + for (;;){ + jskip(p); + if (**p == '}'){ (*p)++; break; } + char* k = jparse_string(p); + jskip(p); if (**p == ':') (*p)++; + JVal* kid = jparse_at(p); + jpush(v, k ? k : "", kid); + free(k); + jskip(p); + if (**p == ',') (*p)++; + else if (**p == '}'){ (*p)++; break; } + else if (!**p) break; + } + return v; + } + if (c == '['){ + (*p)++; JVal* v = jnew(JARR); + for (;;){ + jskip(p); + if (**p == ']'){ (*p)++; break; } + jpush(v, 0, jparse_at(p)); + jskip(p); + if (**p == ',') (*p)++; + else if (**p == ']'){ (*p)++; break; } + else if (!**p) break; + } + return v; + } + if (c == '"'){ JVal* v = jnew(JSTR); v->s = jparse_string(p); return v; } + if (!strncmp(*p, "true", 4)){ *p += 4; JVal* v = jnew(JBOOL); v->b = 1; return v; } + if (!strncmp(*p, "false", 5)){ *p += 5; JVal* v = jnew(JBOOL); v->b = 0; return v; } + if (!strncmp(*p, "null", 4)){ *p += 4; return jnew(JNULL); } + { char* end; double d = strtod(*p, &end); if (end != *p){ *p = end; JVal* v = jnew(JNUM); v->num = d; return v; } } + (*p)++; /* unparsable: step past it */ + return jnew(JNULL); +} +static JVal* jparse(const char* text){ const char* p = text; return jparse_at(&p); } + +static JVal* jget(JVal* v, const char* key){ + if (!v || v->t != JOBJ) return 0; + for (int i = 0; i < v->n; i++) if (v->keys[i] && !strcmp(v->keys[i], key)) return v->kids[i]; + return 0; +} +static JVal* jat(JVal* v, int i){ return (v && i >= 0 && i < v->n) ? v->kids[i] : 0; } +static const char* jstr(JVal* v, const char* def){ return (v && v->t == JSTR && v->s) ? v->s : def; } +static int jint(JVal* v, int def){ return (v && v->t == JNUM) ? (int)v->num : def; } +static int jbool(JVal* v, int def){ return v ? (v->t == JBOOL ? v->b : (v->t == JNUM ? v->num != 0 : def)) : def; } +/* dotted lookup: jpath(msg, "params.textDocument.uri") */ +static JVal* jpath(JVal* v, const char* path){ + char buf[256]; snprintf(buf, sizeof(buf), "%s", path); + char* save = 0; + for (char* tok = strtok_r(buf, ".", &save); tok; tok = strtok_r(0, ".", &save)){ + v = jget(v, tok); + if (!v) return 0; + } + return v; +} + +/* ---------- writing -------------------------------------------------------*/ +typedef struct { char* b; size_t n, cap; } JSB; +static void jsb_ensure(JSB* s, size_t add){ + if (s->n + add + 1 > s->cap){ s->cap = (s->n + add + 1) * 2; s->b = realloc(s->b, s->cap); } +} +static void jsb_add(JSB* s, const char* z, size_t l){ jsb_ensure(s, l); memcpy(s->b + s->n, z, l); s->n += l; s->b[s->n] = 0; } +static void jsb_puts(JSB* s, const char* z){ jsb_add(s, z, strlen(z)); } +static void jsb_putc(JSB* s, char c){ jsb_add(s, &c, 1); } +static void jsb_putf(JSB* s, const char* fmt, ...){ + char tmp[1024]; + va_list ap; va_start(ap, fmt); + int n = vsnprintf(tmp, sizeof(tmp), fmt, ap); + va_end(ap); + if (n < (int)sizeof(tmp)){ jsb_add(s, tmp, n); return; } + char* big = malloc(n + 1); + va_start(ap, fmt); vsnprintf(big, n + 1, fmt, ap); va_end(ap); + jsb_add(s, big, n); free(big); +} +/* Escape a UTF-8 string as a JSON string literal, quotes included. */ +static void jsb_str(JSB* s, const char* z){ + jsb_putc(s, '"'); + if (!z) z = ""; + for (const unsigned char* p = (const unsigned char*)z; *p; p++){ + switch (*p){ + case '"': jsb_puts(s, "\\\""); break; + case '\\': jsb_puts(s, "\\\\"); break; + case '\n': jsb_puts(s, "\\n"); break; + case '\r': jsb_puts(s, "\\r"); break; + case '\t': jsb_puts(s, "\\t"); break; + default: + if (*p < 0x20) jsb_putf(s, "\\u%04x", *p); + else jsb_putc(s, (char)*p); + } + } + jsb_putc(s, '"'); +} +static void jsb_kv_str(JSB* s, const char* k, const char* v){ jsb_str(s, k); jsb_putc(s, ':'); jsb_str(s, v); } +static void jsb_kv_int(JSB* s, const char* k, long v){ jsb_str(s, k); jsb_putf(s, ":%ld", v); } +static void jsb_kv_bool(JSB* s, const char* k, int v){ jsb_str(s, k); jsb_puts(s, v ? ":true" : ":false"); } +#endif /* LUDIC_JSON_H */ diff --git a/tools/ludic-tools/ludic_lsp.c b/tools/ludic-tools/ludic_lsp.c new file mode 100644 index 00000000..9a2099a8 --- /dev/null +++ b/tools/ludic-tools/ludic_lsp.c @@ -0,0 +1,1265 @@ +/* ============================================================================ + * ludic-lsp — the Ludic language server. + * + * Speaks LSP 3.17 over stdio, so it is the IDE-agnostic half of this toolchain: + * VS Code, JetBrains, Neovim, Helix, Emacs, Sublime and Zed all drive the same + * binary, and an editor nobody has written a plugin for yet still gets + * completion, diagnostics, hover and formatting by pointing at it. + * + * It answers structural questions itself (from ludic_index.h, which keeps + * parsing after an error the way a compiler must not), and defers questions of + * correctness to `ludicc` — the compiler stays the single source of truth about + * whether a program is valid. + * + * Markdown is a first-class input: a ```ludic fence in a .md gets the same + * highlighting, hover and diagnostics as a .ludic file. + * ==========================================================================*/ +#define _GNU_SOURCE +#include "ludic_workspace.h" +#include "ludic_fmt.h" +#include "ludic_json.h" +#include + +/* ---------- server state --------------------------------------------------*/ +static LIndex X; +static char* g_ludicc = 0; /* path to the compiler, if we found one */ +static int g_indent = 2; +static int g_compiler_diags = 1; +static int g_shutdown = 0; +static int g_utf8_positions = 0; /* the client accepted utf-8 offsets */ +static FILE* g_log = 0; + +static void lg(const char* fmt, ...){ + if (!g_log) return; + va_list ap; va_start(ap, fmt); vfprintf(g_log, fmt, ap); va_end(ap); + fputc('\n', g_log); fflush(g_log); +} + +/* ---------- framing -------------------------------------------------------*/ +static void send_raw(const char* body){ + printf("Content-Length: %zu\r\n\r\n%s", strlen(body), body); + fflush(stdout); +} +static void send_result(JVal* id, const char* result_json){ + JSB s = {0}; + jsb_puts(&s, "{\"jsonrpc\":\"2.0\",\"id\":"); + if (!id) jsb_puts(&s, "null"); + else if (id->t == JSTR) jsb_str(&s, id->s); + else jsb_putf(&s, "%ld", (long)id->num); + jsb_puts(&s, ",\"result\":"); + jsb_puts(&s, result_json && *result_json ? result_json : "null"); + jsb_puts(&s, "}"); + send_raw(s.b); free(s.b); +} +static void send_notify(const char* method, const char* params_json){ + JSB s = {0}; + jsb_puts(&s, "{\"jsonrpc\":\"2.0\",\"method\":"); + jsb_str(&s, method); + jsb_puts(&s, ",\"params\":"); + jsb_puts(&s, params_json ? params_json : "null"); + jsb_puts(&s, "}"); + send_raw(s.b); free(s.b); +} +/* Read one Content-Length framed message. NULL at EOF. */ +static char* read_message(void){ + char line[8192]; + long len = -1; + for (;;){ + if (!fgets(line, sizeof(line), stdin)) return 0; + if (line[0] == '\r' || line[0] == '\n') break; + if (!strncasecmp(line, "Content-Length:", 15)) len = strtol(line + 15, 0, 10); + } + if (len <= 0) return 0; + char* buf = malloc(len + 1); + long got = 0; + while (got < len){ + size_t r = fread(buf + got, 1, len - got, stdin); + if (!r) break; + got += r; + } + buf[got] = 0; + return buf; +} + +/* ---------- position helpers ---------------------------------------------*/ +static int pos_char(LDoc* D, int off){ + if (g_utf8_positions){ + int line = ldoc_line_of(D, off); + return off - D->lex.linestart[line]; + } + return ldoc_col_of(D, off); +} +static void put_pos(JSB* s, LDoc* D, int off){ + jsb_putf(s, "{\"line\":%d,\"character\":%d}", ldoc_line_of(D, off), pos_char(D, off)); +} +static void put_range(JSB* s, LDoc* D, int a, int b){ + jsb_puts(s, "{\"start\":"); put_pos(s, D, a); + jsb_puts(s, ",\"end\":"); put_pos(s, D, b); + jsb_puts(s, "}"); +} +static void put_location(JSB* s, LDoc* D, int a, int b){ + jsb_puts(s, "{\"uri\":"); jsb_str(s, D->uri); + jsb_puts(s, ",\"range\":"); put_range(s, D, a, b); + jsb_puts(s, "}"); +} + +/* ---------- diagnostics ---------------------------------------------------*/ +typedef struct { LDoc* doc; LDiag* v; int n, cap; } DiagSet; +static void diag_add(DiagSet* ds, LDoc* D, int line, int col, int endline, int endcol, int sev, const char* msg){ + if (ds->n >= ds->cap){ ds->cap = ds->cap ? ds->cap * 2 : 16; ds->v = realloc(ds->v, ds->cap * sizeof(LDiag)); } + LDiag* d = &ds->v[ds->n++]; + memset(d, 0, sizeof(*d)); + d->line = line; d->col = col; d->endline = endline; d->endcol = endcol; d->severity = sev; + snprintf(d->msg, sizeof(d->msg), "%s", msg); + snprintf(d->path, sizeof(d->path), "%s", D->path); +} +/* Structural problems we can see without the compiler, cheaply, on every + * keystroke: unbalanced delimiters and unterminated literals. */ +static void diag_structural(LDoc* D, DiagSet* ds){ + int stack[512], top = 0; + for (int i = 0; i < D->lex.n; i++){ + const LTok* t = &D->lex.v[i]; + if (t->bad){ + const char* m = t->kind == LT_STR ? "unterminated string literal" + : t->kind == LT_CHAR ? "unterminated character literal" + : "unexpected character"; + diag_add(ds, D, ldoc_line_of(D, t->start), pos_char(D, t->start), + ldoc_line_of(D, t->end), pos_char(D, t->end), 1, m); + continue; + } + if (t->kind != LT_OP || ltok_len(t) != 1) continue; + char c = D->text[t->start]; + if (c == '{' || c == '(' || c == '['){ if (top < 512) stack[top++] = i; } + else if (c == '}' || c == ')' || c == ']'){ + if (!top){ + char m[64]; snprintf(m, sizeof(m), "unmatched '%c'", c); + diag_add(ds, D, ldoc_line_of(D, t->start), pos_char(D, t->start), + ldoc_line_of(D, t->end), pos_char(D, t->end), 1, m); + } else { + int o = stack[--top]; + char oc = D->text[D->lex.v[o].start]; + char want = oc == '{' ? '}' : oc == '(' ? ')' : ']'; + if (want != c){ + char m[80]; snprintf(m, sizeof(m), "expected '%c' to close '%c', found '%c'", want, oc, c); + diag_add(ds, D, ldoc_line_of(D, t->start), pos_char(D, t->start), + ldoc_line_of(D, t->end), pos_char(D, t->end), 1, m); + } + } + } + } + for (int k = 0; k < top; k++){ + const LTok* t = &D->lex.v[stack[k]]; + char m[64]; snprintf(m, sizeof(m), "unclosed '%c'", D->text[t->start]); + diag_add(ds, D, ldoc_line_of(D, t->start), pos_char(D, t->start), + ldoc_line_of(D, t->end), pos_char(D, t->end), 1, m); + } +} + +/* Ask the compiler. `ludicc --fmt` runs lex + parse + validate and stops before + * codegen, which is exactly the checking pass we want and costs milliseconds. + * A fragment (an imported file with no `game` block) is not a program on its + * own, so we check the unit root that pulls it in and let the file paths in the + * compiler's own output route each error back to the right buffer. */ +static void diag_compiler(LDoc* D, DiagSet* ds){ + if (!g_ludicc || !g_compiler_diags) return; + /* A .md is Ludic only inside its fences; the file as a whole is prose, and + * handing it to the compiler yields errors about the prose. The fences are + * still checked structurally, which is as far as a fragment can be checked + * anyway — most of them are deliberately incomplete snippets. */ + if (D->is_markdown) return; + LDoc* root = lw_unit_root(&X, D); + if (!root) root = D->is_unit ? D : 0; + if (!root) return; + /* Paths reach us from URIs the editor sends, and they end up in a shell + * command. A quote in a path would let a filename run something; refuse + * rather than escape, since no real Ludic file needs one. */ + if (strchr(root->path, '\'') || strchr(g_ludicc, '\'')) return; + + /* the compiler reads from disk; an unsaved buffer would be checked stale */ + char cmd[PATH_MAX * 2 + 64]; + snprintf(cmd, sizeof(cmd), "'%s' '%s' --fmt -o /dev/null 2>&1", g_ludicc, root->path); + FILE* p = popen(cmd, "r"); + if (!p) return; + char line[4096]; + char msg[512]; msg[0] = 0; + int have = 0, lineno = 0; + while (fgets(line, sizeof(line), p)){ + size_t n = strlen(line); + while (n && (line[n-1] == '\n' || line[n-1] == '\r')) line[--n] = 0; + int ln; + char rest[1024]; + if (sscanf(line, "ludicc: error: line %d: %1023[^\n]", &ln, rest) == 2){ + if (have){ diag_add(ds, root, lineno - 1, 0, lineno - 1, 200, 1, msg); } + lineno = ln; snprintf(msg, sizeof(msg), "%s", rest); have = 1; + continue; + } + /* the follow-up line names the file the error is really in */ + char path[1024]; + if (have && sscanf(line, " %1023[^:]:%d |", path, &ln) == 2){ + LDoc* target = lw_ensure(&X, path); + if (!target) target = root; + int l0 = ln - 1; + int end = 200; + if (l0 >= 0 && l0 < target->lex.nline){ + int s0 = target->lex.linestart[l0]; + int e0 = (l0 + 1 < target->lex.nline) ? target->lex.linestart[l0+1] - 1 : (int)strlen(target->text); + end = pos_char(target, e0 > s0 ? e0 : s0); + } + diag_add(ds, target, l0, 0, l0, end, 1, msg); + have = 0; msg[0] = 0; + continue; + } + if (!have && !strncmp(line, "ludicc: ", 8) && !strstr(line, "error: line")){ + diag_add(ds, root, 0, 0, 0, 0, 1, line + 8); + } + } + if (have) diag_add(ds, root, lineno - 1, 0, lineno - 1, 200, 1, msg); + pclose(p); +} + +/* Publish for every document that got a diagnostic, and clear the rest. + * + * Markdown gets none. A fence in prose is a snippet — `system Move { … }` with + * an elision mark, or a body shown without its enclosing `game` block — so + * almost every "error" found there is the documentation doing its job. The + * useful half of the server still applies to fences: highlighting, hover, + * completion, go-to-definition and formatting are never wrong on a snippet. */ +static void publish_diagnostics(LDoc* D){ + DiagSet ds = {0}; + if (!D->is_markdown) diag_structural(D, &ds); + /* only bother the compiler when the buffer itself parses — otherwise we are + * reporting the same brace twice, in two different dialects */ + int structural = ds.n; + if (!structural) diag_compiler(D, &ds); + + /* Every document that has a diagnostic now, plus every document that had + * one last time — otherwise fixing an error in an imported file leaves its + * marker on screen forever, because nothing would ever publish an empty + * list for that file again. */ + LDoc* touched[128]; int nt = 0; + touched[nt++] = D; + for (int i = 0; i < ds.n; i++){ + LDoc* T = lw_by_path(&X, ds.v[i].path); + if (!T) continue; + int seen = 0; for (int k = 0; k < nt; k++) if (touched[k] == T) seen = 1; + if (!seen && nt < 128) touched[nt++] = T; + } + for (int i = 0; i < X.n && nt < 128; i++){ + if (!X.d[i]->had_diags) continue; + int seen = 0; for (int k = 0; k < nt; k++) if (touched[k] == X.d[i]) seen = 1; + if (!seen) touched[nt++] = X.d[i]; + } + for (int k = 0; k < nt; k++){ + LDoc* T = touched[k]; + T->had_diags = 0; + JSB s = {0}; + jsb_puts(&s, "{\"uri\":"); jsb_str(&s, T->uri); + jsb_puts(&s, ",\"diagnostics\":["); + int first = 1; + for (int i = 0; i < ds.n; i++){ + if (strcmp(ds.v[i].path, T->path)) continue; + if (!first) jsb_putc(&s, ','); + first = 0; + T->had_diags = 1; + jsb_putf(&s, "{\"range\":{\"start\":{\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%d}}", + ds.v[i].line < 0 ? 0 : ds.v[i].line, ds.v[i].col, + ds.v[i].endline < 0 ? 0 : ds.v[i].endline, ds.v[i].endcol); + jsb_putf(&s, ",\"severity\":%d,\"source\":\"ludic\",\"message\":", ds.v[i].severity); + jsb_str(&s, ds.v[i].msg); + jsb_putc(&s, '}'); + } + jsb_puts(&s, "]}"); + send_notify("textDocument/publishDiagnostics", s.b); + free(s.b); + } + free(ds.v); +} + +/* ---------- semantic tokens ----------------------------------------------*/ +/* The legend, in the order the client will index into. */ +static const char* STOK_TYPES[] = { + "keyword","type","struct","class","namespace","function","parameter", + "variable","property","enumMember","number","string","comment","operator", + "decorator", 0 +}; +enum { STM_DECL = 1, STM_READONLY = 2, STM_DEFLIB = 4 }; +static const char* STOK_MODS[] = { "declaration","readonly","defaultLibrary", 0 }; + +static int sem_type_of(int cls, int* mods){ + *mods = 0; + switch (cls){ + case SC_KEYWORD: return 0; + case SC_TYPE: *mods = STM_DEFLIB; return 1; + case SC_COMPONENT: return 2; + case SC_ARCHETYPE: return 3; + case SC_SCENE: return 4; + case SC_LAYER: return 4; + case SC_UI: return 3; + case SC_WIDGET: *mods = STM_DEFLIB; return 3; + case SC_SYSTEM: return 5; + case SC_FUNCTION: return 5; + case SC_BUILTIN: *mods = STM_DEFLIB; return 5; + case SC_PARAM: return 6; + case SC_VARIABLE: return 7; + case SC_MODVAR: return 7; + case SC_CONST: *mods = STM_READONLY; return 7; + case SC_PROP: return 8; + case SC_FIELD: return 8; + case SC_PHASE: *mods = STM_READONLY | STM_DEFLIB; return 9; + case SC_NUMBER: return 10; + case SC_STRING: return 11; + case SC_COMMENT: return 12; + case SC_OPERATOR: return 13; + case SC_ANNOTATION: return 14; + default: return -1; + } +} +static char* semantic_tokens(LDoc* D, int from_line, int to_line){ + lw_classify(&X, D); + JSB s = {0}; + jsb_puts(&s, "{\"data\":["); + int prev_line = 0, prev_char = 0, first = 1; + for (int i = 0; i < D->lex.n; i++){ + const LTok* t = &D->lex.v[i]; + if (t->kind == LT_NL || t->kind == LT_EOF) continue; + if (t->line < from_line || (to_line >= 0 && t->line > to_line)) continue; + int mods; int ty = sem_type_of(D->cls[i], &mods); + if (ty < 0) continue; + int line = t->line; + int ch = pos_char(D, t->start); + int len = g_utf8_positions ? ltok_len(t) : lutf16_len(D->text + t->start, ltok_len(t)); + if (len <= 0) continue; + int dl = line - prev_line; + int dc = dl ? ch : ch - prev_char; + if (!first) jsb_putc(&s, ','); + first = 0; + jsb_putf(&s, "%d,%d,%d,%d,%d", dl, dc, len, ty, mods); + prev_line = line; prev_char = ch; + } + jsb_puts(&s, "]}"); + return s.b; +} + +/* ---------- symbol presentation ------------------------------------------*/ +static int lsp_symbol_kind(int k){ + switch (k){ /* LSP SymbolKind numbers */ + case LS_UNIT: return 2; /* Module */ + case LS_COMPONENT: return 23; /* Struct */ + case LS_FIELD: return 8; /* Field */ + case LS_ARCHETYPE: return 5; /* Class */ + case LS_CONST: return 14; /* Constant */ + case LS_VAR: return 13; /* Variable */ + case LS_FN: return 12; /* Function */ + case LS_EXTERN: return 12; + case LS_SYSTEM: return 6; /* Method */ + case LS_UI: return 5; + case LS_WIDGET: return 14; + case LS_SCENE: return 3; /* Namespace */ + case LS_LAYER: return 3; + case LS_PARAM: return 13; + case LS_LOCAL: return 13; + case LS_QUERYVAR: return 13; + case LS_STATE: return 22; /* EnumMember */ + case LS_IMPORT: return 2; + default: return 13; + } +} +static int sym_is_outline(int k){ + switch (k){ + case LS_UNIT: case LS_COMPONENT: case LS_FIELD: case LS_ARCHETYPE: + case LS_CONST: case LS_VAR: case LS_FN: case LS_EXTERN: case LS_SYSTEM: + case LS_UI: case LS_WIDGET: case LS_SCENE: case LS_LAYER: + return 1; + default: return 0; + } +} +/* DocumentSymbol is a tree; emit children of `parent` recursively. */ +static void put_doc_symbols(JSB* s, LDoc* D, int parent){ + int first = 1; + jsb_putc(s, '['); + for (int i = 0; i < D->nsym; i++){ + LSym* y = &D->sym[i]; + if (y->parent != parent || !sym_is_outline(y->kind) || !y->name[0]) continue; + if (!first) jsb_putc(s, ','); + first = 0; + jsb_puts(s, "{\"name\":"); jsb_str(s, y->name); + jsb_puts(s, ",\"detail\":"); jsb_str(s, y->detail); + jsb_putf(s, ",\"kind\":%d,\"range\":", lsp_symbol_kind(y->kind)); + int a = y->start, b = y->end; + if (y->body_end > y->end && y->body_start >= y->start){ a = y->start; b = y->body_end; } + put_range(s, D, a, b); + jsb_puts(s, ",\"selectionRange\":"); put_range(s, D, y->start, y->end); + jsb_puts(s, ",\"children\":"); + put_doc_symbols(s, D, i); + jsb_putc(s, '}'); + } + jsb_putc(s, ']'); +} + +/* ---------- hover ---------------------------------------------------------*/ +static void hover_markdown(JSB* s, const char* code, const char* doc){ + JSB m = {0}; + jsb_puts(&m, "```ludic\n"); + jsb_puts(&m, code); + jsb_puts(&m, "\n```"); + if (doc && *doc){ jsb_puts(&m, "\n\n"); jsb_puts(&m, doc); } + jsb_puts(s, "{\"contents\":{\"kind\":\"markdown\",\"value\":"); + jsb_str(s, m.b); + jsb_puts(s, "}}"); + free(m.b); +} + +/* ---------- completion ----------------------------------------------------*/ +enum { CI_TEXT = 1, CI_METHOD = 2, CI_FUNCTION = 3, CI_FIELD = 5, CI_VARIABLE = 6, + CI_CLASS = 7, CI_PROPERTY = 10, CI_UNIT = 11, CI_VALUE = 12, CI_ENUM = 13, + CI_KEYWORD = 14, CI_SNIPPET = 15, CI_CONSTANT = 21, CI_STRUCT = 22, CI_EVENT = 23 }; + +typedef struct { JSB* s; int first; } CompOut; +static void comp_item(CompOut* c, const char* label, int kind, const char* detail, const char* doc, const char* insert){ + if (!c->first) jsb_putc(c->s, ','); + c->first = 0; + jsb_puts(c->s, "{\"label\":"); jsb_str(c->s, label); + jsb_putf(c->s, ",\"kind\":%d", kind); + if (detail && *detail){ jsb_puts(c->s, ",\"detail\":"); jsb_str(c->s, detail); } + if (doc && *doc){ + jsb_puts(c->s, ",\"documentation\":{\"kind\":\"markdown\",\"value\":"); + jsb_str(c->s, doc); + jsb_putc(c->s, '}'); + } + if (insert && *insert){ + jsb_puts(c->s, ",\"insertText\":"); jsb_str(c->s, insert); + jsb_puts(c->s, ",\"insertTextFormat\":2"); + } + jsb_putc(c->s, '}'); +} +static void comp_words(CompOut* c, const char** words, int kind, const char* detail){ + for (int i = 0; words[i]; i++) comp_item(c, words[i], kind, detail, 0, 0); +} +static void comp_builtins(CompOut* c){ + for (int i = 0; LUDIC_BUILTINS[i].name; i++) + comp_item(c, LUDIC_BUILTINS[i].name, CI_FUNCTION, LUDIC_BUILTINS[i].sig, LUDIC_BUILTINS[i].doc, 0); + for (int i = 0; LUDIC_INTRINSICS[i].name; i++) + comp_item(c, LUDIC_INTRINSICS[i].name, CI_FUNCTION, LUDIC_INTRINSICS[i].sig, LUDIC_INTRINSICS[i].doc, 0); +} +static int comp_kind_of(int symkind){ + switch (symkind){ + case LS_COMPONENT: return CI_STRUCT; + case LS_ARCHETYPE: return CI_CLASS; + case LS_CONST: return CI_CONSTANT; + case LS_VAR: return CI_VARIABLE; + case LS_FN: case LS_EXTERN: return CI_FUNCTION; + case LS_SYSTEM: return CI_EVENT; + case LS_UI: return CI_CLASS; + case LS_WIDGET: return CI_CONSTANT; + case LS_SCENE: return CI_UNIT; + case LS_LAYER: return CI_UNIT; + case LS_FIELD: return CI_FIELD; + default: return CI_VARIABLE; + } +} +/* Everything the compilation unit declares, plus the locals in scope here. + * `types_only` is for the positions where nothing but a component or archetype + * can appear — a query's term list, a `spawn`, a type annotation — and there a + * local variable is not a candidate at all. */ +static void comp_scope(CompOut* c, LDoc* D, int off, int types_only){ + if (!types_only) + for (int i = 0; i < D->nsym; i++){ + LSym* y = &D->sym[i]; + if (!lsym_is_local(y->kind)) continue; + if (off < y->body_start || off > y->body_end) continue; + comp_item(c, y->name, CI_VARIABLE, y->detail[0] ? y->detail : y->type, 0, 0); + } + LDoc* rel[128]; int n = lw_related(&X, D, rel, 128); + for (int i = 0; i < n; i++) + for (int k = 0; k < rel[i]->nsym; k++){ + LSym* y = &rel[i]->sym[k]; + if (!lsym_is_toplevel(y->kind) || y->kind == LS_UNIT) continue; + if (types_only && !(y->kind == LS_COMPONENT || y->kind == LS_ARCHETYPE)) continue; + comp_item(c, y->name, comp_kind_of(y->kind), y->detail, y->doc, 0); + } +} + +/* ---------- URI/doc plumbing ---------------------------------------------*/ +static LDoc* doc_of(JVal* msg){ + const char* uri = jstr(jpath(msg, "params.textDocument.uri"), 0); + if (!uri) return 0; + LDoc* D = lw_by_uri(&X, uri); + if (D) return D; + char* path = lw_uri_to_path(uri); + D = lw_ensure(&X, path); + free(path); + return D; +} +static int off_of(JVal* msg, LDoc* D, const char* base){ + char kl[128], kc[128]; + snprintf(kl, sizeof(kl), "%s.line", base); + snprintf(kc, sizeof(kc), "%s.character", base); + int line = jint(jpath(msg, kl), 0), ch = jint(jpath(msg, kc), 0); + if (g_utf8_positions){ + if (line < 0 || line >= D->lex.nline) return 0; + int s0 = D->lex.linestart[line]; + int e0 = (line + 1 < D->lex.nline) ? D->lex.linestart[line + 1] : (int)strlen(D->text); + int off = s0 + ch; + return off > e0 ? e0 : off; + } + return ldoc_offset_of(D, line, ch); +} + +/* ---------- request handlers ---------------------------------------------*/ +static void on_initialize(JVal* msg, JVal* id){ + JVal* root = jpath(msg, "params.rootUri"); + if (root && root->t == JSTR) X.root = lw_uri_to_path(root->s); + else { + JVal* folders = jpath(msg, "params.workspaceFolders"); + JVal* f0 = jat(folders, 0); + const char* u = jstr(jget(f0, "uri"), 0); + if (u) X.root = lw_uri_to_path(u); + } + /* the client may prefer plain byte offsets; take it if offered, it is both + * cheaper and exactly what our lexer already produces */ + JVal* enc = jpath(msg, "params.capabilities.general.positionEncodings"); + if (enc) for (int i = 0; i < enc->n; i++){ + const char* e = jstr(jat(enc, i), ""); + if (!strcmp(e, "utf-8")){ g_utf8_positions = 1; break; } + } + JVal* init = jpath(msg, "params.initializationOptions"); + const char* cc = jstr(jget(init, "compilerPath"), 0); + if (cc && *cc){ free(g_ludicc); g_ludicc = strdup(cc); } + if (jget(init, "indentSize")) g_indent = jint(jget(init, "indentSize"), 2); + if (jget(init, "compilerDiagnostics")) g_compiler_diags = jbool(jget(init, "compilerDiagnostics"), 1); + + /* find the compiler if nobody told us where it is */ + if (!g_ludicc && X.root){ + char p[PATH_MAX]; + snprintf(p, sizeof(p), "%s/build/ludicc", X.root); + if (!access(p, X_OK)) g_ludicc = strdup(p); + } + if (!g_ludicc && !access("build/ludicc", X_OK)) g_ludicc = strdup("build/ludicc"); + + if (X.root) lw_scan(&X, X.root, 0); + lg("initialize root=%s compiler=%s docs=%d", X.root ? X.root : "-", g_ludicc ? g_ludicc : "-", X.n); + + JSB s = {0}; + jsb_puts(&s, "{\"capabilities\":{"); + jsb_puts(&s, "\"positionEncoding\":"); + jsb_str(&s, g_utf8_positions ? "utf-8" : "utf-16"); + jsb_puts(&s, ",\"textDocumentSync\":{\"openClose\":true,\"change\":1,\"save\":{\"includeText\":false}}"); + jsb_puts(&s, ",\"documentSymbolProvider\":true"); + jsb_puts(&s, ",\"workspaceSymbolProvider\":true"); + jsb_puts(&s, ",\"definitionProvider\":true"); + jsb_puts(&s, ",\"declarationProvider\":true"); + jsb_puts(&s, ",\"referencesProvider\":true"); + jsb_puts(&s, ",\"documentHighlightProvider\":true"); + jsb_puts(&s, ",\"hoverProvider\":true"); + jsb_puts(&s, ",\"renameProvider\":{\"prepareProvider\":true}"); + jsb_puts(&s, ",\"documentFormattingProvider\":true"); + jsb_puts(&s, ",\"documentRangeFormattingProvider\":true"); + jsb_puts(&s, ",\"foldingRangeProvider\":true"); + jsb_puts(&s, ",\"documentLinkProvider\":{\"resolveProvider\":false}"); + jsb_puts(&s, ",\"inlayHintProvider\":true"); + jsb_puts(&s, ",\"completionProvider\":{\"triggerCharacters\":[\".\",\"@\",\"[\",\" \"],\"resolveProvider\":false}"); + jsb_puts(&s, ",\"signatureHelpProvider\":{\"triggerCharacters\":[\"(\",\",\"]}"); + jsb_puts(&s, ",\"semanticTokensProvider\":{\"legend\":{\"tokenTypes\":["); + for (int i = 0; STOK_TYPES[i]; i++){ if (i) jsb_putc(&s, ','); jsb_str(&s, STOK_TYPES[i]); } + jsb_puts(&s, "],\"tokenModifiers\":["); + for (int i = 0; STOK_MODS[i]; i++){ if (i) jsb_putc(&s, ','); jsb_str(&s, STOK_MODS[i]); } + jsb_puts(&s, "]},\"full\":true,\"range\":true}"); + jsb_puts(&s, "},\"serverInfo\":{\"name\":\"ludic-lsp\",\"version\":\"1.0.0\"}}"); + send_result(id, s.b); + free(s.b); +} + +static void on_document_symbol(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "[]"); return; } + JSB s = {0}; + put_doc_symbols(&s, D, -1); + send_result(id, s.b); + free(s.b); +} + +static void on_workspace_symbol(JVal* msg, JVal* id){ + const char* q = jstr(jpath(msg, "params.query"), ""); + JSB s = {0}; jsb_putc(&s, '['); + int first = 1; + for (int i = 0; i < X.n; i++){ + LDoc* D = X.d[i]; + for (int k = 0; k < D->nsym; k++){ + LSym* y = &D->sym[k]; + if (!sym_is_outline(y->kind) || !y->name[0]) continue; + if (*q && !strcasestr(y->name, q)) continue; + if (!first) jsb_putc(&s, ','); + first = 0; + jsb_puts(&s, "{\"name\":"); jsb_str(&s, y->name); + jsb_putf(&s, ",\"kind\":%d,\"location\":", lsp_symbol_kind(y->kind)); + put_location(&s, D, y->start, y->end); + if (D->unit[0]){ jsb_puts(&s, ",\"containerName\":"); jsb_str(&s, D->unit); } + jsb_putc(&s, '}'); + } + } + jsb_putc(&s, ']'); + send_result(id, s.b); + free(s.b); +} + +/* What does this exact token refer to? Every feature that needs to know two + * occurrences are the same thing — go-to-definition, find-usages, rename, + * highlight — goes through here, so they cannot disagree with each other. */ +static int resolve_tok(LDoc* D, int tok, LDoc** owner, int* symidx){ + *owner = 0; *symidx = -1; + if (tok < 0) return -1; + if (D->lex.v[tok].kind != LT_ID && D->lex.v[tok].kind != LT_STR) return -1; + char name[96]; ltok_text(&D->lex, tok, name, sizeof(name)); + + /* The token may BE a declaration's name — a component, a field, a + * parameter, a query binding. Those resolve to themselves, which is what + * makes hover work on the left-hand side of `for (a, b) in query [...]` + * where the binding is not yet inside its own scope. */ + for (int i = 0; i < D->nsym; i++) + if (D->sym[i].tok == tok){ *owner = D; *symidx = i; return tok; } + + /* a member: resolve through the receiver's component */ + int prev = ltok_prev_sig(&D->lex, tok); + if (prev >= 0 && ltok_is(&D->lex, prev, ".")){ + LDoc* co = 0; + int comp = lw_receiver_component(&X, D, prev, &co); + if (comp >= 0 && co){ + for (int i = 0; i < co->nsym; i++) + if (co->sym[i].kind == LS_FIELD && co->sym[i].parent == comp && !strcmp(co->sym[i].name, name)){ + *owner = co; *symidx = i; return tok; + } + } + return tok; + } + int l = lw_find_local(D, name, D->lex.v[tok].start); + if (l >= 0){ *owner = D; *symidx = l; return tok; } + LDoc* o = 0; int t = lw_find_top(&X, D, name, &o); + if (t >= 0){ *owner = o; *symidx = t; return tok; } + return tok; +} +static int resolve_at(LDoc* D, int off, LDoc** owner, int* symidx){ + return resolve_tok(D, ldoc_tok_at(D, off), owner, symidx); +} +/* Occurrences of one symbol, found by resolving each candidate token rather + * than by matching text. It is the difference between renaming a component + * field `x` and renaming every `x` in the project. */ +typedef void (*OccFn)(void* ctx, LDoc* T, int tok); +static void for_each_occurrence(LDoc* from, LDoc* target_doc, int target_sym, OccFn fn, void* ctx){ + char want[96]; + lcpy(want, sizeof(want), target_doc->text + target_doc->sym[target_sym].start, + target_doc->sym[target_sym].end - target_doc->sym[target_sym].start); + + /* A local binding cannot be referred to from another file, so there is no + * reason to walk the unit for one. */ + LDoc* single[1] = { from }; + LDoc* rel[128]; + int n; + if (lsym_is_local(target_doc->sym[target_sym].kind)){ rel[0] = single[0]; n = 1; } + else n = lw_related(&X, from, rel, 128); + + for (int i = 0; i < n; i++){ + LDoc* T = rel[i]; + for (int k = 0; k < T->lex.n; k++){ + if (T->lex.v[k].kind != LT_ID) continue; + char w[96]; ltok_text(&T->lex, k, w, sizeof(w)); + if (strcmp(w, want)) continue; /* cheap filter first */ + LDoc* o = 0; int sy = -1; + resolve_tok(T, k, &o, &sy); + if (o == target_doc && sy == target_sym) fn(ctx, T, k); + } + } +} + +static void on_definition(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "null"); return; } + int off = off_of(msg, D, "params.position"); + /* an import string jumps to the file */ + int tok = ldoc_tok_at(D, off); + if (tok >= 0 && D->lex.v[tok].kind == LT_STR){ + int p = ltok_prev_sig(&D->lex, tok); + if (p >= 0 && ltok_is(&D->lex, p, "import")){ + char rel[512]; ltok_text(&D->lex, tok, rel, sizeof(rel)); + int n = (int)strlen(rel); if (n >= 2){ memmove(rel, rel + 1, n - 2); rel[n-2] = 0; } + char* dir = lw_dirname(D->path); + char* full = lw_join(dir, rel); free(dir); + LDoc* T = lw_ensure(&X, full); free(full); + if (T){ JSB s = {0}; put_location(&s, T, 0, 0); send_result(id, s.b); free(s.b); return; } + } + } + LDoc* owner = 0; int sym = -1; + resolve_at(D, off, &owner, &sym); + if (!owner || sym < 0){ send_result(id, "null"); return; } + JSB s = {0}; + put_location(&s, owner, owner->sym[sym].start, owner->sym[sym].end); + send_result(id, s.b); + free(s.b); +} + +static void on_hover(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "null"); return; } + int off = off_of(msg, D, "params.position"); + int tok = ldoc_tok_at(D, off); + if (tok < 0){ send_result(id, "null"); return; } + char name[128]; ltok_text(&D->lex, tok, name, sizeof(name)); + + LDoc* owner = 0; int sym = -1; + resolve_at(D, off, &owner, &sym); + JSB s = {0}; + if (owner && sym >= 0){ + LSym* y = &owner->sym[sym]; + char code[320]; + snprintf(code, sizeof(code), "%s", y->detail[0] ? y->detail : y->name); + char doc[768]; + snprintf(doc, sizeof(doc), "%s", y->doc); + if (owner != D){ + size_t n = strlen(doc); + snprintf(doc + n, sizeof(doc) - n, "%s_declared in %s_", n ? "\n\n" : "", strrchr(owner->path, '/') ? strrchr(owner->path, '/') + 1 : owner->path); + } + hover_markdown(&s, code, doc); + send_result(id, s.b); free(s.b); return; + } + const LBuiltin* bi = lud_lookup(LUDIC_BUILTINS, name); + const char* origin = "runtime builtin — provided by `rt_` in runtime/native"; + if (!bi){ bi = lud_lookup(LUDIC_INTRINSICS, name); origin = "compiler intrinsic — lowers straight to libc / the OS"; } + if (bi){ + char doc[768]; snprintf(doc, sizeof(doc), "%s\n\n_%s_", bi->doc, origin); + hover_markdown(&s, bi->sig, doc); + send_result(id, s.b); free(s.b); return; + } + if (D->lex.v[tok].kind == LT_PHASE){ + hover_markdown(&s, name, "A system phase. Each frame runs `Input` -> `FixedUpdate` -> `Update` -> `LateUpdate` -> `Render`; `Start` runs once at boot."); + send_result(id, s.b); free(s.b); return; + } + if (D->lex.v[tok].kind == LT_TYPE){ + static const struct { const char* n; const char* d; } TY[] = { + {"int","32-bit integer."}, + {"fixed","Q16.16 fixed-point. `fx(i)` widens an int, `flr(f)` truncates back."}, + {"bool","Boolean."}, + {"entity","An entity handle. `self()` gives the one the current query is on."}, + {"str","A string literal."}, + {"ptr","A raw pointer — the runtime's floor, not for game code."}, + {"void","No value."}, + {0,0} + }; + for (int i = 0; TY[i].n; i++) if (!strcmp(TY[i].n, name)){ + hover_markdown(&s, name, TY[i].d); + send_result(id, s.b); free(s.b); return; + } + } + free(s.b); + send_result(id, "null"); +} + +/* ---------- references, highlight, rename --------------------------------*/ +typedef struct { JSB* s; int first; int mode; const char* newname; LDoc* cur; } OccOut; +enum { OCC_LOCATION, OCC_HIGHLIGHT }; + +static void occ_emit(void* ctx, LDoc* T, int tok){ + OccOut* o = (OccOut*)ctx; + if (o->mode == OCC_HIGHLIGHT && T != o->cur) return; + if (!o->first) jsb_putc(o->s, ','); + o->first = 0; + if (o->mode == OCC_HIGHLIGHT){ + jsb_puts(o->s, "{\"range\":"); + put_range(o->s, T, T->lex.v[tok].start, T->lex.v[tok].end); + jsb_puts(o->s, ",\"kind\":1}"); + } else { + put_location(o->s, T, T->lex.v[tok].start, T->lex.v[tok].end); + } +} + +static void refs_common(JVal* msg, JVal* id, int mode){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "[]"); return; } + int off = off_of(msg, D, "params.position"); + LDoc* owner = 0; int sym = -1; + int tok = resolve_at(D, off, &owner, &sym); + if (tok < 0 || !owner || sym < 0){ send_result(id, "[]"); return; } + JSB s = {0}; jsb_putc(&s, '['); + OccOut o = { &s, 1, mode, 0, D }; + for_each_occurrence(D, owner, sym, occ_emit, &o); + jsb_putc(&s, ']'); + send_result(id, s.b); free(s.b); +} +static void on_references(JVal* msg, JVal* id){ refs_common(msg, id, OCC_LOCATION); } +static void on_document_highlight(JVal* msg, JVal* id){ refs_common(msg, id, OCC_HIGHLIGHT); } + +static void on_prepare_rename(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "null"); return; } + int off = off_of(msg, D, "params.position"); + LDoc* owner = 0; int sym = -1; + int tok = resolve_at(D, off, &owner, &sym); + /* Refusing beats renaming the wrong thing: if we cannot say what a name + * refers to, we cannot say which occurrences of it mean the same name. */ + if (tok < 0 || !owner || sym < 0 || D->lex.v[tok].kind != LT_ID){ send_result(id, "null"); return; } + JSB s = {0}; + jsb_puts(&s, "{\"range\":"); + put_range(&s, D, D->lex.v[tok].start, D->lex.v[tok].end); + jsb_puts(&s, ",\"placeholder\":"); + { char w[96]; ltok_text(&D->lex, tok, w, sizeof(w)); jsb_str(&s, w); } + jsb_putc(&s, '}'); + send_result(id, s.b); free(s.b); +} + +/* Rename collects per-file edit lists, because the LSP workspace edit is keyed + * by URI and a symbol can occur in several files of one unit. */ +typedef struct { LDoc* doc; JSB edits; int first; } FileEdits; +typedef struct { FileEdits f[64]; int n; const char* newname; } RenameOut; + +static void rename_collect(void* ctx, LDoc* T, int tok){ + RenameOut* r = (RenameOut*)ctx; + FileEdits* fe = 0; + for (int i = 0; i < r->n; i++) if (r->f[i].doc == T) fe = &r->f[i]; + if (!fe){ + if (r->n >= 64) return; + fe = &r->f[r->n++]; + memset(fe, 0, sizeof(*fe)); + fe->doc = T; fe->first = 1; + } + if (!fe->first) jsb_putc(&fe->edits, ','); + fe->first = 0; + jsb_puts(&fe->edits, "{\"range\":"); + put_range(&fe->edits, T, T->lex.v[tok].start, T->lex.v[tok].end); + jsb_puts(&fe->edits, ",\"newText\":"); + jsb_str(&fe->edits, r->newname); + jsb_putc(&fe->edits, '}'); +} + +static void on_rename(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + const char* newname = jstr(jpath(msg, "params.newName"), 0); + if (!D || !newname || !*newname){ send_result(id, "null"); return; } + int off = off_of(msg, D, "params.position"); + LDoc* owner = 0; int sym = -1; + int tok = resolve_at(D, off, &owner, &sym); + if (tok < 0 || !owner || sym < 0){ send_result(id, "null"); return; } + + RenameOut r; memset(&r, 0, sizeof(r)); r.newname = newname; + for_each_occurrence(D, owner, sym, rename_collect, &r); + + JSB s = {0}; + jsb_puts(&s, "{\"changes\":{"); + for (int i = 0; i < r.n; i++){ + if (i) jsb_putc(&s, ','); + jsb_str(&s, r.f[i].doc->uri); + jsb_putc(&s, ':'); + jsb_putc(&s, '['); + jsb_puts(&s, r.f[i].edits.b ? r.f[i].edits.b : ""); + jsb_putc(&s, ']'); + free(r.f[i].edits.b); + } + jsb_puts(&s, "}}"); + send_result(id, s.b); free(s.b); +} + +static void on_formatting(JVal* msg, JVal* id, int ranged){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "null"); return; } + int tab = jint(jpath(msg, "params.options.tabSize"), g_indent); + if (tab < 1 || tab > 8) tab = g_indent; + char* out = D->is_markdown ? ludic_format_markdown(D->raw, tab) : ludic_format(D->raw, tab); + /* A whole-document replacement is the honest edit: the formatter's unit of + * work is the file, and a partial rewrite could not fix indentation that + * depends on lines outside the range. Range formatting therefore formats + * the document too — every editor accepts that, and it never surprises. */ + (void)ranged; + int nline = D->lex.nline; + int endline = nline > 0 ? nline - 1 : 0; + int endchar = 0; + { + int s0 = nline ? D->lex.linestart[endline] : 0; + int e0 = (int)strlen(D->text); + endchar = g_utf8_positions ? e0 - s0 : lutf16_len(D->text + s0, e0 - s0); + } + JSB s = {0}; + jsb_putf(&s, "[{\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":%d,\"character\":%d}},\"newText\":", endline, endchar); + jsb_str(&s, out); + jsb_puts(&s, "}]"); + send_result(id, s.b); + free(s.b); free(out); +} + +static void on_folding(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "[]"); return; } + JSB s = {0}; jsb_putc(&s, '['); int first = 1; + for (int i = 0; i < D->lex.n; i++){ + const LTok* t = &D->lex.v[i]; + if (t->kind != LT_OP || ltok_len(t) != 1 || D->text[t->start] != '{') continue; + int m = D->match[i]; + if (m < 0) continue; + int a = t->line, b = D->lex.v[m].line; + if (b <= a) continue; + if (!first) jsb_putc(&s, ','); + first = 0; + jsb_putf(&s, "{\"startLine\":%d,\"endLine\":%d,\"kind\":\"region\"}", a, b - 1); + } + /* runs of comment lines fold as one block */ + for (int i = 0; i < D->lex.n; ){ + if (D->lex.v[i].kind != LT_COMMENT || !lw_first_on_line(D, i)){ i++; continue; } + int a = D->lex.v[i].line, last = a, j = i; + while (j < D->lex.n){ + if (D->lex.v[j].kind == LT_NL){ j++; continue; } + if (D->lex.v[j].kind == LT_COMMENT && lw_first_on_line(D, j) && D->lex.v[j].line <= last + 1){ last = D->lex.v[j].line; j++; continue; } + break; + } + if (last > a){ + if (!first) jsb_putc(&s, ','); + first = 0; + jsb_putf(&s, "{\"startLine\":%d,\"endLine\":%d,\"kind\":\"comment\"}", a, last); + } + i = j; + } + jsb_putc(&s, ']'); + send_result(id, s.b); free(s.b); +} + +static void on_document_link(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "[]"); return; } + JSB s = {0}; jsb_putc(&s, '['); int first = 1; + for (int i = 0; i < D->lex.n; i++){ + if (D->lex.v[i].kind != LT_STR) continue; + int p = ltok_prev_sig(&D->lex, i); + if (p < 0 || !ltok_is(&D->lex, p, "import")) continue; + char rel[512]; ltok_text(&D->lex, i, rel, sizeof(rel)); + int n = (int)strlen(rel); if (n >= 2){ memmove(rel, rel + 1, n - 2); rel[n-2] = 0; } + char* dir = lw_dirname(D->path); + char* full = lw_join(dir, rel); free(dir); + char* uri = lw_path_to_uri(full); + if (!first) jsb_putc(&s, ','); + first = 0; + jsb_puts(&s, "{\"range\":"); + put_range(&s, D, D->lex.v[i].start + 1, D->lex.v[i].end - 1); + jsb_puts(&s, ",\"target\":"); jsb_str(&s, uri); jsb_putc(&s, '}'); + free(uri); free(full); + } + jsb_putc(&s, ']'); + send_result(id, s.b); free(s.b); +} + +/* Query bindings read `for (p, v) in query [Pos, Vel]` — the types are one + * lookup away but invisible at the use site, so show them inline. */ +static void on_inlay_hint(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "[]"); return; } + JSB s = {0}; jsb_putc(&s, '['); int first = 1; + for (int i = 0; i < D->nsym; i++){ + LSym* y = &D->sym[i]; + if (y->kind != LS_QUERYVAR || !y->type[0]) continue; + if (!first) jsb_putc(&s, ','); + first = 0; + char label[128]; snprintf(label, sizeof(label), ": %s", y->type); + jsb_puts(&s, "{\"position\":"); put_pos(&s, D, y->end); + jsb_puts(&s, ",\"label\":"); jsb_str(&s, label); + jsb_puts(&s, ",\"kind\":1,\"paddingLeft\":false}"); + } + jsb_putc(&s, ']'); + send_result(id, s.b); free(s.b); +} + +static void on_signature_help(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "null"); return; } + int off = off_of(msg, D, "params.position"); + /* walk out to the call we are inside */ + int depth = 0, callee = -1, arg = 0; + for (int i = D->lex.n - 1; i >= 0; i--){ + const LTok* t = &D->lex.v[i]; + if (t->start >= off) continue; + if (t->kind != LT_OP || ltok_len(t) != 1) continue; + char c = D->text[t->start]; + if (c == ')') depth++; + else if (c == '('){ + if (depth == 0){ callee = ltok_prev_sig(&D->lex, i); + for (int k = i + 1; k < D->lex.n && D->lex.v[k].start < off; k++) + if (ltok_is(&D->lex, k, ",")) arg++; + break; } + depth--; + } + } + if (callee < 0 || D->lex.v[callee].kind != LT_ID){ send_result(id, "null"); return; } + char name[128]; ltok_text(&D->lex, callee, name, sizeof(name)); + const char* sig = 0; const char* doc = ""; + const LBuiltin* bi = lud_lookup(LUDIC_BUILTINS, name); + if (!bi) bi = lud_lookup(LUDIC_INTRINSICS, name); + if (bi){ sig = bi->sig; doc = bi->doc; } + else { + LDoc* o = 0; int t = lw_find_top(&X, D, name, &o); + if (t >= 0 && (o->sym[t].kind == LS_FN || o->sym[t].kind == LS_EXTERN)){ sig = o->sym[t].detail; doc = o->sym[t].doc; } + } + if (!sig){ send_result(id, "null"); return; } + JSB s = {0}; + jsb_puts(&s, "{\"signatures\":[{\"label\":"); jsb_str(&s, sig); + if (doc && *doc){ jsb_puts(&s, ",\"documentation\":"); jsb_str(&s, doc); } + jsb_putf(&s, "}],\"activeSignature\":0,\"activeParameter\":%d}", arg); + send_result(id, s.b); free(s.b); +} + +static void on_completion(JVal* msg, JVal* id){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "[]"); return; } + int off = off_of(msg, D, "params.position"); + JSB s = {0}; + jsb_puts(&s, "{\"isIncomplete\":false,\"items\":["); + CompOut c = { &s, 1 }; + + /* what comes immediately before the cursor decides everything */ + int tok = -1; + for (int i = D->lex.n - 1; i >= 0; i--){ + int k = D->lex.v[i].kind; + if (k == LT_NL || k == LT_EOF || k == LT_COMMENT) continue; + if (D->lex.v[i].end <= off){ tok = i; break; } + } + /* skip the partial word being typed */ + int anchor = tok; + if (anchor >= 0 && D->lex.v[anchor].kind == LT_ID && D->lex.v[anchor].end >= off) anchor = ltok_prev_sig(&D->lex, anchor); + + /* Inside an unclosed `[` we are listing query terms, where the only things + * that can appear are components and archetypes — including after a comma, + * which is why this is a scan rather than a look at the previous token. */ + int in_query_terms = 0; + { + int depth = 0; + for (int i = anchor; i >= 0; i--){ + const LTok* t = &D->lex.v[i]; + if (t->kind != LT_OP || ltok_len(t) != 1) continue; + char ch = D->text[t->start]; + if (ch == ']') depth++; + else if (ch == '['){ if (!depth){ in_query_terms = 1; break; } depth--; } + else if (ch == '{' || ch == '}') break; /* left the clause */ + } + } + + int done = 0; + if (in_query_terms){ comp_scope(&c, D, off, 1); done = 1; } + else if (anchor >= 0){ + /* member access: only that component's fields */ + if (ltok_is(&D->lex, anchor, ".")){ + LDoc* co = 0; + int comp = lw_receiver_component(&X, D, anchor, &co); + if (comp >= 0 && co){ + for (int i = 0; i < co->nsym; i++) + if (co->sym[i].kind == LS_FIELD && co->sym[i].parent == comp) + comp_item(&c, co->sym[i].name, CI_FIELD, co->sym[i].detail, co->sym[i].doc, 0); + } + done = 1; + } + else if (ltok_is(&D->lex, anchor, "phase")){ comp_words(&c, LUDIC_PHASES, CI_ENUM, "system phase"); done = 1; } + else if (ltok_is(&D->lex, anchor, ":") || ltok_is(&D->lex, anchor, "->")){ + comp_words(&c, LUDIC_TYPES, CI_KEYWORD, "built-in type"); + comp_scope(&c, D, off, 1); + done = 1; + } + else if (ltok_is(&D->lex, anchor, "spawn")){ comp_scope(&c, D, off, 1); done = 1; } + else if (ltok_is(&D->lex, anchor, "enter")){ + LDoc* rel[128]; int n = lw_related(&X, D, rel, 128); + for (int i = 0; i < n; i++) + for (int k = 0; k < rel[i]->nsym; k++) + if (rel[i]->sym[k].kind == LS_SCENE) + comp_item(&c, rel[i]->sym[k].name, CI_UNIT, rel[i]->sym[k].detail, rel[i]->sym[k].doc, 0); + done = 1; + } + else if (D->lex.v[anchor].kind == LT_OP && ltok_len(&D->lex.v[anchor]) == 1 && D->text[D->lex.v[anchor].start] == '@'){ + comp_item(&c, "deterministic", CI_KEYWORD, "@deterministic", "Marks a system as reproducible given the same inputs.", 0); + done = 1; + } + } + if (!done && lw_in_ui_body(D, off)){ + comp_words(&c, LUDIC_WIDGETS, CI_CLASS, "widget"); + comp_words(&c, LUDIC_WIDGET_PROPS, CI_PROPERTY, "widget property"); + } + if (!done){ + comp_words(&c, LUDIC_KW_DECL, CI_KEYWORD, "declaration"); + comp_words(&c, LUDIC_KW_STMT, CI_KEYWORD, "statement"); + comp_words(&c, LUDIC_KW_CLAUSE, CI_KEYWORD, "clause"); + comp_words(&c, LUDIC_TYPES, CI_KEYWORD, "built-in type"); + comp_builtins(&c); + comp_scope(&c, D, off, 0); + /* the shapes people actually type */ + comp_item(&c, "system", CI_SNIPPET, "system … phase … { }", "A system with a phase and a body.", + "system ${1:Name} phase ${2|Start,Input,FixedUpdate,Update,LateUpdate,Render|} {\n $0\n}"); + comp_item(&c, "system+query", CI_SNIPPET, "system … query … { }", "A system that runs once per matching entity.", + "system ${1:Name} phase ${2|Update,FixedUpdate,LateUpdate,Render,Input|}\n query (${3:p}) [${4:Pos}]\n{\n $0\n}"); + comp_item(&c, "component", CI_SNIPPET, "component … { }", "A component with typed fields.", + "component ${1:Name} { ${2:x}: ${3:int} = ${4:0} }"); + comp_item(&c, "archetype", CI_SNIPPET, "archetype … { }", "An entity kind bundling components.", + "archetype ${1:Name} {\n ${2:Pos}\n}"); + comp_item(&c, "for-query", CI_SNIPPET, "for (…) in query […] { }", "Iterate matching entities.", + "for (${1:p}) in query [${2:Pos}] {\n $0\n}"); + comp_item(&c, "scene", CI_SNIPPET, "scene … { layer … }", "A scene with one layer.", + "scene ${1:Name} {\n on enter { $2 }\n layer ${3:Main} {\n $0\n }\n}"); + } + jsb_puts(&s, "]}"); + send_result(id, s.b); + free(s.b); +} + +/* ---------- document lifecycle -------------------------------------------*/ +static void refresh(LDoc* D){ ldoc_reindex(D); lw_classify(&X, D); } + +static void on_did_open(JVal* msg){ + const char* uri = jstr(jpath(msg, "params.textDocument.uri"), 0); + const char* text = jstr(jpath(msg, "params.textDocument.text"), 0); + if (!uri) return; + char* path = lw_uri_to_path(uri); + LDoc* D = lw_by_path(&X, path); + if (!D){ D = lw_new_doc(path, strdup(text ? text : "")); lw_add(&X, D); } + else if (text) ldoc_settext(D, strdup(text)); + free(path); + D->open = 1; + D->version = jint(jpath(msg, "params.textDocument.version"), 0); + refresh(D); + publish_diagnostics(D); +} +static void on_did_change(JVal* msg){ + LDoc* D = doc_of(msg); + if (!D) return; + JVal* changes = jpath(msg, "params.contentChanges"); + JVal* last = jat(changes, changes ? changes->n - 1 : 0); + const char* text = jstr(jget(last, "text"), 0); + if (!text) return; + ldoc_settext(D, strdup(text)); + D->version = jint(jpath(msg, "params.textDocument.version"), D->version + 1); + refresh(D); + /* structural feedback only while typing; the compiler waits for a save, + * because it reads the file from disk and would otherwise report the + * previous save's errors against the current buffer */ + DiagSet ds = {0}; + if (!D->is_markdown) diag_structural(D, &ds); + JSB s = {0}; + jsb_puts(&s, "{\"uri\":"); jsb_str(&s, D->uri); + jsb_puts(&s, ",\"diagnostics\":["); + D->had_diags = ds.n > 0; + for (int i = 0; i < ds.n; i++){ + if (i) jsb_putc(&s, ','); + jsb_putf(&s, "{\"range\":{\"start\":{\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%d}},\"severity\":%d,\"source\":\"ludic\",\"message\":", + ds.v[i].line, ds.v[i].col, ds.v[i].endline, ds.v[i].endcol, ds.v[i].severity); + jsb_str(&s, ds.v[i].msg); + jsb_putc(&s, '}'); + } + jsb_puts(&s, "]}"); + send_notify("textDocument/publishDiagnostics", s.b); + free(s.b); free(ds.v); +} +static void on_did_save(JVal* msg){ + LDoc* D = doc_of(msg); + if (!D) return; + const char* text = jstr(jpath(msg, "params.text"), 0); + if (text) ldoc_settext(D, strdup(text)); + else { char* disk = lw_readfile(D->path, 0); if (disk) ldoc_settext(D, disk); } + refresh(D); + publish_diagnostics(D); +} +static void on_did_close(JVal* msg){ + LDoc* D = doc_of(msg); + if (!D) return; + D->open = 0; + char* disk = lw_readfile(D->path, 0); + if (disk){ ldoc_settext(D, disk); refresh(D); } +} + +/* ---------- dispatch ------------------------------------------------------*/ +static void handle(JVal* msg){ + const char* method = jstr(jget(msg, "method"), 0); + JVal* id = jget(msg, "id"); + if (!method) return; + lg("<- %s", method); + + if (!strcmp(method, "initialize")){ on_initialize(msg, id); return; } + if (!strcmp(method, "initialized")) return; + if (!strcmp(method, "shutdown")){ g_shutdown = 1; send_result(id, "null"); return; } + if (!strcmp(method, "exit")){ exit(g_shutdown ? 0 : 1); } + + if (!strcmp(method, "textDocument/didOpen")){ on_did_open(msg); return; } + if (!strcmp(method, "textDocument/didChange")){ on_did_change(msg); return; } + if (!strcmp(method, "textDocument/didSave")){ on_did_save(msg); return; } + if (!strcmp(method, "textDocument/didClose")){ on_did_close(msg); return; } + if (!strcmp(method, "workspace/didChangeConfiguration")){ + JVal* cfg = jpath(msg, "params.settings.ludic"); + const char* cc = jstr(jget(cfg, "compilerPath"), 0); + if (cc && *cc){ free(g_ludicc); g_ludicc = strdup(cc); } + if (jget(cfg, "indentSize")) g_indent = jint(jget(cfg, "indentSize"), g_indent); + if (jget(cfg, "compilerDiagnostics")) g_compiler_diags = jbool(jget(cfg, "compilerDiagnostics"), 1); + return; + } + if (!strcmp(method, "workspace/didChangeWatchedFiles")){ + JVal* ch = jpath(msg, "params.changes"); + for (int i = 0; ch && i < ch->n; i++){ + const char* u = jstr(jget(jat(ch, i), "uri"), 0); + if (!u) continue; + char* p = lw_uri_to_path(u); + LDoc* D = lw_by_path(&X, p); + if (D && !D->open){ char* disk = lw_readfile(p, 0); if (disk){ ldoc_settext(D, disk); refresh(D); } } + else if (!D) lw_ensure(&X, p); + free(p); + } + return; + } + + if (!strcmp(method, "textDocument/documentSymbol")){ on_document_symbol(msg, id); return; } + if (!strcmp(method, "workspace/symbol")){ on_workspace_symbol(msg, id); return; } + if (!strcmp(method, "textDocument/definition") || + !strcmp(method, "textDocument/declaration") || + !strcmp(method, "textDocument/typeDefinition")){ on_definition(msg, id); return; } + if (!strcmp(method, "textDocument/hover")){ on_hover(msg, id); return; } + if (!strcmp(method, "textDocument/references")){ on_references(msg, id); return; } + if (!strcmp(method, "textDocument/documentHighlight")){ on_document_highlight(msg, id); return; } + if (!strcmp(method, "textDocument/prepareRename")){ on_prepare_rename(msg, id); return; } + if (!strcmp(method, "textDocument/rename")){ on_rename(msg, id); return; } + if (!strcmp(method, "textDocument/formatting")){ on_formatting(msg, id, 0); return; } + if (!strcmp(method, "textDocument/rangeFormatting")){ on_formatting(msg, id, 1); return; } + if (!strcmp(method, "textDocument/foldingRange")){ on_folding(msg, id); return; } + if (!strcmp(method, "textDocument/documentLink")){ on_document_link(msg, id); return; } + if (!strcmp(method, "textDocument/inlayHint")){ on_inlay_hint(msg, id); return; } + if (!strcmp(method, "textDocument/signatureHelp")){ on_signature_help(msg, id); return; } + if (!strcmp(method, "textDocument/completion")){ on_completion(msg, id); return; } + if (!strcmp(method, "textDocument/semanticTokens/full") || + !strcmp(method, "textDocument/semanticTokens/range")){ + LDoc* D = doc_of(msg); + if (!D){ send_result(id, "null"); return; } + int from = 0, to = -1; + JVal* r = jpath(msg, "params.range"); + if (r){ from = jint(jpath(msg, "params.range.start.line"), 0); to = jint(jpath(msg, "params.range.end.line"), -1); } + char* out = semantic_tokens(D, from, to); + send_result(id, out); + free(out); + return; + } + + /* an unknown request still needs an answer, or the client hangs */ + if (id) send_result(id, "null"); +} + +static const char* USAGE = +"ludic-lsp — the Ludic language server (LSP 3.17 over stdio)\n" +"\n" +"usage: ludic-lsp [--stdio] [--compiler PATH] [--log FILE] [--no-compiler-diagnostics]\n" +"\n" +"Editors normally launch this themselves. --stdio is accepted and ignored;\n" +"stdio is the only transport.\n"; + +int main(int argc, char** argv){ + signal(SIGPIPE, SIG_IGN); + for (int i = 1; i < argc; i++){ + if (!strcmp(argv[i], "--compiler") && i + 1 < argc) g_ludicc = strdup(argv[++i]); + else if (!strcmp(argv[i], "--log") && i + 1 < argc) g_log = fopen(argv[++i], "w"); + else if (!strcmp(argv[i], "--no-compiler-diagnostics")) g_compiler_diags = 0; + else if (!strcmp(argv[i], "--indent") && i + 1 < argc) g_indent = atoi(argv[++i]); + else if (!strcmp(argv[i], "--stdio")) ; + else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){ fputs(USAGE, stdout); return 0; } + else if (!strcmp(argv[i], "--version")){ puts("ludic-lsp 1.0.0"); return 0; } + } + for (;;){ + char* raw = read_message(); + if (!raw) break; + JVal* msg = jparse(raw); + handle(msg); + jfree(msg); + free(raw); + } + return 0; +} diff --git a/tools/ludic-tools/ludic_syntax.h b/tools/ludic-tools/ludic_syntax.h new file mode 100644 index 00000000..df1fa73f --- /dev/null +++ b/tools/ludic-tools/ludic_syntax.h @@ -0,0 +1,321 @@ +/* ============================================================================ + * ludic_syntax.h — the lexical layer shared by every Ludic editor tool. + * + * One lexer, one vocabulary. `ludic-fmt`, `ludic-lsp` and the generated + * TextMate grammar all read their keyword/builtin/type tables from here, so an + * addition to the language shows up in every editor at once instead of drifting + * across six hand-maintained copies. + * + * Unlike the compiler's lexer (compiler/ludicc.c) this one is written for + * editors: it keeps comments, keeps newlines, records byte spans for every + * token, and never exits on bad input — a stray character becomes an LT_ERR + * token and lexing continues, because a file being typed into is malformed most + * of the time. + * ==========================================================================*/ +#ifndef LUDIC_SYNTAX_H +#define LUDIC_SYNTAX_H + +#include +#include +#include +#include + +/* ---------- token kinds ---------------------------------------------------*/ +enum { + LT_EOF, LT_NL, LT_COMMENT, + LT_ID, /* a plain identifier */ + LT_KW, /* a reserved word (see KEYWORDS) */ + LT_TYPE, /* a built-in type name: int fixed bool entity str ptr void */ + LT_PHASE, /* Start Input FixedUpdate Update LateUpdate Render */ + LT_BOOL, /* true false */ + LT_INT, LT_FLOAT, LT_STR, LT_CHAR, + LT_ANNO, /* @deterministic — the '@' and the name as one token */ + LT_OP, + LT_ERR +}; + +typedef struct { + int kind; + int start, end; /* byte offsets into the source buffer */ + int line; /* 0-based */ + int bad; /* set on an unterminated string / stray character */ +} LTok; + +typedef struct { + LTok* v; int n, cap; + const char* src; + int* linestart; int nline, caplin; +} LLex; + +/* ---------- the vocabulary ------------------------------------------------*/ +/* Reserved words, grouped so editors can colour them differently. The groups + * mirror the compiler's parser: anything parse_decl() dispatches on is a + * declaration keyword, anything stmt() dispatches on is a statement keyword. */ +static const char* LUDIC_KW_DECL[] = { + "game","module","import","component","struct","archetype","ui","scene","layer", + "const","var","export","fn","pure","extern","system","edge","start","on", 0 +}; +static const char* LUDIC_KW_CLAUSE[] = { + "phase","query","reads","writes","needs","uses", + "requires","ensures","invariant","effects", 0 +}; +static const char* LUDIC_KW_STMT[] = { + "let","return","if","else","when","while","for","in","spawn","despawn", + "match","machine","state","become","enter","where","and","or","not", + "break","continue","new", 0 +}; +static const char* LUDIC_TYPES[] = { + "int","fixed","bool","entity","str","ptr","void", 0 +}; +static const char* LUDIC_PHASES[] = { + "Start","Input","FixedUpdate","Update","LateUpdate","Render", 0 +}; +static const char* LUDIC_WIDGETS[] = { + "panel","col","row","label","button","image","spacer", 0 +}; +static const char* LUDIC_WIDGET_PROPS[] = { + "id","text","skin","image","align","w","h","pad","gap","size","font", + "inset","grow","bg","fg","border","focus","x","y", 0 +}; + +/* A builtin is a name the runtime provides (`clear(c)` -> rt_clear). An + * intrinsic is a name the compiler lowers directly to libc/OS. Editors treat + * both as "standard library", but the signatures differ, so they stay apart. */ +typedef struct { const char* name; const char* sig; const char* doc; } LBuiltin; + +static const LBuiltin LUDIC_BUILTINS[] = { + {"min","min(a: int, b: int) -> int","Smaller of two integers."}, + {"max","max(a: int, b: int) -> int","Larger of two integers."}, + {"abs","abs(a: int) -> int","Absolute value."}, + {"clamp","clamp(v: int, lo: int, hi: int) -> int","Constrain v to [lo, hi]."}, + {"seed","seed(i: int)","Seed the deterministic RNG."}, + {"rng_range","rng_range(lo: int, hi: int) -> int","Deterministic integer in [lo, hi]."}, + {"rng_chance","rng_chance(pct: int) -> bool","True pct% of the time, deterministically."}, + {"fx","fx(i: int) -> fixed","Widen an int to Q16.16 fixed-point."}, + {"flr","flr(f: fixed) -> int","Truncate a fixed-point value toward zero."}, + {"map_size","map_size(w: int, h: int)","Set the tilemap dimensions."}, + {"map_row","map_row(y: int, row: str)","Fill one tilemap row from a string."}, + {"tile","tile(x: int, y: int) -> int","Tile code at a map cell."}, + {"clear","clear(color: int)","Clear the framebuffer to a 0xRRGGBB colour."}, + {"present","present()","Push the framebuffer to the window (or out.ppm when headless)."}, + {"fill_rect","fill_rect(x: int, y: int, w: int, h: int, color: int)","Filled rectangle."}, + {"frame_rect","frame_rect(x: int, y: int, w: int, h: int, color: int)","One-pixel rectangle outline."}, + {"put_px","put_px(x: int, y: int, color: int)","Write a single pixel."}, + {"text","text(x: int, y: int, s: str, color: int, scale: int)","Draw text with the built-in 5x7 bitmap font."}, + {"text_int","text_int(x: int, y: int, n: int, color: int, scale: int)","Draw an integer with the 5x7 bitmap font."}, + {"font_load","font_load(path: str) -> int","Load a TrueType .ttf/.ttc; returns a font id."}, + {"text_ttf","text_ttf(font: int, x: int, y: int, utf8: str, color: int, px: int)","Draw UTF-8 text with a TrueType font."}, + {"text_w","text_w(font: int, utf8: str, px: int) -> int","Advance width of the string, in pixels."}, + {"text_h","text_h(font: int, px: int) -> int","Line height of the font, in pixels."}, + {"image_load","image_load(path: str) -> int","Decode a PNG into an image id."}, + {"draw_image","draw_image(id: int, x: int, y: int)","Blit an image at its natural size."}, + {"draw_image_scaled","draw_image_scaled(id: int, x: int, y: int, w: int, h: int)","Blit an image stretched to w x h."}, + {"draw_9slice","draw_9slice(id: int, x: int, y: int, w: int, h: int, inset: int)","Nine-slice an image across a w x h box."}, + {"load_png","load_png(path: str) -> int","Decode a PNG as a 16x16 sprite sheet; returns the first sprite id."}, + {"load_sprites","load_sprites(path: str)","Load the sprite sheet used by draw_sprite."}, + {"draw_sprite","draw_sprite(id: int, x: int, y: int)","Blit a sprite."}, + {"draw_sprite_scaled","draw_sprite_scaled(id: int, x: int, y: int, scale: int)","Blit a sprite at an integer scale."}, + {"ui_build","ui_build()","Construct every declared `ui` tree (loads skins and images)."}, + {"ui_open","ui_open(id: int)","Make a ui tree active and focus its first button."}, + {"ui_tick","ui_tick(key: int)","Feed a key to the UI: w/s move focus, space/enter activate."}, + {"ui_render","ui_render()","Lay out and draw the active ui tree."}, + {"ui_clicked","ui_clicked(id: int) -> bool","True on the frame a widget was activated."}, + {"ui_set_text","ui_set_text(id: int, s: str)","Replace a widget's text."}, + {"ui_set_int","ui_set_int(id: int, n: int)","Replace a widget's text with a number."}, + {"ui_focus","ui_focus(id: int)","Move keyboard focus to a widget."}, + {"ui_focused","ui_focused() -> int","Id of the focused widget."}, + {"ui_visible","ui_visible(id: int, on: bool)","Show or hide a widget subtree."}, + {"key","key() -> int","Key code pressed this frame, 0 if none."}, + {"reg","reg(i: int) -> int","Read one of the 64 integer resources shared by systems."}, + {"setreg","setreg(i: int, v: int)","Write one of the 64 integer resources."}, + {"self","self() -> entity","The entity of the innermost query loop."}, + {"save","save()","Write a binary snapshot of the whole ECS world."}, + {"load","load() -> bool","Restore the snapshot; false if there is none."}, + {"status","status(s: str)","Set the one-line status message."}, + {"print_int","print_int(i: int)","Print an integer to stdout."}, + {"quit","quit()","Stop the frame loop and exit."}, + {0,0,0} +}; + +static const LBuiltin LUDIC_INTRINSICS[] = { + {"mem_alloc","mem_alloc(n: int) -> ptr","Allocate n bytes (malloc)."}, + {"mem_realloc","mem_realloc(p: ptr, n: int) -> ptr","Resize a block to n bytes, preserving its contents (realloc)."}, + {"os_argc","os_argc() -> int","Number of command-line arguments, argv[0] included."}, + {"os_arg","os_arg(i: int) -> str","The i-th command-line argument."}, + {"file_stderr","file_stderr() -> ptr","The standard error stream, for file_write."}, + {"mem_free","mem_free(p: ptr)","Release an allocation."}, + {"mem_copy","mem_copy(dst: ptr, src: ptr, n: int)","memcpy."}, + {"mem_set","mem_set(p: ptr, byte: int, n: int)","memset."}, + {"peek8","peek8(p: ptr, off: int) -> int","Read one byte."}, + {"poke8","poke8(p: ptr, off: int, v: int)","Write one byte."}, + {"peek32","peek32(p: ptr, off: int) -> int","Read a 32-bit word."}, + {"poke32","poke32(p: ptr, off: int, v: int)","Write a 32-bit word."}, + {"peekp","peekp(p: ptr, off: int) -> ptr","Read a pointer-sized word."}, + {"pokep","pokep(p: ptr, off: int, v: ptr)","Write a pointer-sized word."}, + {"peekf","peekf(p: ptr, off: int) -> fixed","Read a fixed-point word."}, + {"pokef","pokef(p: ptr, off: int, v: fixed)","Write a fixed-point word."}, + {"ptr_add","ptr_add(p: ptr, off: int) -> ptr","Offset a pointer by bytes."}, + {"ptr_null","ptr_null() -> ptr","The null pointer."}, + {"ptr_is_null","ptr_is_null(p: ptr) -> bool","Null test."}, + {"as_fixed","as_fixed(i: int) -> fixed","Reinterpret an int as fixed (no conversion)."}, + {"as_int","as_int(f: fixed) -> int","Reinterpret a fixed as int (no conversion)."}, + {"file_open","file_open(path: str, mode: str) -> ptr","fopen."}, + {"file_read","file_read(f: ptr, buf: ptr, n: int) -> int","fread."}, + {"file_write","file_write(f: ptr, buf: ptr, n: int) -> int","fwrite."}, + {"file_seek","file_seek(f: ptr, off: int, whence: int) -> int","fseek."}, + {"file_tell","file_tell(f: ptr) -> int","ftell."}, + {"file_close","file_close(f: ptr)","fclose."}, + {"read_byte","read_byte() -> int","Read one byte from stdin, -1 at EOF."}, + {"write_byte","write_byte(b: int)","Write one byte to stdout."}, + {"print_str","print_str(s: str)","Write a string to stdout."}, + {"str_len","str_len(s: str) -> int","Length of a string in bytes."}, + {"shl","shl(v: int, n: int) -> int","Shift left."}, + {"shr","shr(v: int, n: int) -> int","Logical shift right."}, + {"band","band(a: int, b: int) -> int","Bitwise and."}, + {"bor","bor(a: int, b: int) -> int","Bitwise or."}, + {"bxor","bxor(a: int, b: int) -> int","Bitwise xor."}, + {"bnot","bnot(a: int) -> int","Bitwise not."}, + {"os_exit","os_exit(code: int)","Terminate the process."}, + {"os_time","os_time() -> int","Seconds since the epoch."}, + {"is_windowed","is_windowed() -> bool","True when the build has a window."}, + {"game_title","game_title() -> str","The name from the `game` declaration."}, + {"win_open","win_open(title: str, w: int, h: int, scale: int)","Open the platform window."}, + {"win_poll","win_poll() -> int","Pump the event queue; returns a key code."}, + {"win_present","win_present(px: ptr, w: int, h: int)","Blit a framebuffer to the window."}, + {"win_running","win_running() -> bool","False once the window has been closed."}, + {"win_close","win_close()","Close the platform window."}, + {0,0,0} +}; + +static int lud_in(const char** set, const char* s){ + for (int i = 0; set[i]; i++) if (!strcmp(set[i], s)) return 1; + return 0; +} +static const LBuiltin* lud_lookup(const LBuiltin* t, const char* s){ + for (int i = 0; t[i].name; i++) if (!strcmp(t[i].name, s)) return &t[i]; + return 0; +} +static int lud_is_keyword(const char* s){ + return lud_in(LUDIC_KW_DECL, s) || lud_in(LUDIC_KW_CLAUSE, s) || lud_in(LUDIC_KW_STMT, s); +} + +/* ---------- lexing --------------------------------------------------------*/ +static void ltok_push(LLex* L, int kind, int start, int end, int line, int bad){ + if (L->n >= L->cap){ L->cap = L->cap ? L->cap * 2 : 512; L->v = realloc(L->v, L->cap * sizeof(LTok)); } + L->v[L->n++] = (LTok){ kind, start, end, line, bad }; +} +static void lline_push(LLex* L, int off){ + if (L->nline >= L->caplin){ L->caplin = L->caplin ? L->caplin * 2 : 256; L->linestart = realloc(L->linestart, L->caplin * sizeof(int)); } + L->linestart[L->nline++] = off; +} + +static const char* LUDIC_OPS2[] = { "->","+=","-=","*=","/=","==","!=","<=",">=","&&","||","..","=>", 0 }; + +/* Lex the whole buffer. Comments and newlines are kept — the formatter needs + * both, and a highlighter needs the comments. */ +static void lud_lex(LLex* L, const char* src){ + memset(L, 0, sizeof(*L)); + L->src = src; + lline_push(L, 0); + int i = 0, line = 0; + while (src[i]){ + char c = src[i]; + if (c == '\n'){ ltok_push(L, LT_NL, i, i + 1, line, 0); i++; line++; lline_push(L, i); continue; } + if (c == ' ' || c == '\t' || c == '\r'){ i++; continue; } + if (c == '#'){ int s = i; while (src[i] && src[i] != '\n') i++; ltok_push(L, LT_COMMENT, s, i, line, 0); continue; } + if (c == '"'){ + int s = i; i++; int bad = 0; + while (src[i] && src[i] != '"' && src[i] != '\n'){ if (src[i] == '\\' && src[i+1]) i += 2; else i++; } + if (src[i] == '"') i++; else bad = 1; + ltok_push(L, LT_STR, s, i, line, bad); continue; + } + if (c == '\''){ + int s = i; i++; int bad = 0; + if (src[i] == '\\' && src[i+1]) i += 2; else if (src[i] && src[i] != '\n') i++; + if (src[i] == '\'') i++; else bad = 1; + ltok_push(L, LT_CHAR, s, i, line, bad); continue; + } + if (isdigit((unsigned char)c)){ + int s = i; + if (c == '0' && (src[i+1] == 'x' || src[i+1] == 'X')){ + i += 2; while (isxdigit((unsigned char)src[i])) i++; + ltok_push(L, LT_INT, s, i, line, 0); continue; + } + while (isdigit((unsigned char)src[i])) i++; + if (src[i] == '.' && isdigit((unsigned char)src[i+1])){ + i++; while (isdigit((unsigned char)src[i])) i++; + ltok_push(L, LT_FLOAT, s, i, line, 0); continue; + } + ltok_push(L, LT_INT, s, i, line, 0); continue; + } + /* @name is one token: an annotation reads as a unit, and the formatter + * must never put a space between the sigil and the name. */ + if (c == '@' && (isalpha((unsigned char)src[i+1]) || src[i+1] == '_')){ + int s = i; i++; while (isalnum((unsigned char)src[i]) || src[i] == '_') i++; + ltok_push(L, LT_ANNO, s, i, line, 0); continue; + } + if (isalpha((unsigned char)c) || c == '_'){ + int s = i; while (isalnum((unsigned char)src[i]) || src[i] == '_') i++; + int len = i - s; char w[128]; + if (len < (int)sizeof(w)){ memcpy(w, src + s, len); w[len] = 0; } else { w[0] = 0; } + int k = LT_ID; + if (!strcmp(w, "true") || !strcmp(w, "false")) k = LT_BOOL; + else if (lud_in(LUDIC_TYPES, w)) k = LT_TYPE; + else if (lud_in(LUDIC_PHASES, w)) k = LT_PHASE; + else if (lud_is_keyword(w)) k = LT_KW; + ltok_push(L, k, s, i, line, 0); continue; + } + { + int matched = 0; + for (int k = 0; LUDIC_OPS2[k]; k++) + if (src[i] == LUDIC_OPS2[k][0] && src[i+1] == LUDIC_OPS2[k][1]){ + ltok_push(L, LT_OP, i, i + 2, line, 0); i += 2; matched = 1; break; + } + if (matched) continue; + } + if (c == ';'){ ltok_push(L, LT_OP, i, i + 1, line, 0); i++; continue; } + if (strchr("+-*/%<>=(){}[],:.!@", c)){ ltok_push(L, LT_OP, i, i + 1, line, 0); i++; continue; } + /* Anything else is an error token — but a whole UTF-8 character's worth + * at a time. Splitting a multi-byte character into one token per byte + * would let a consumer that re-emits tokens (the formatter) put spaces + * inside it and corrupt the file. */ + { + unsigned char u = (unsigned char)c; + int len = u < 0x80 ? 1 : u < 0xE0 ? 2 : u < 0xF0 ? 3 : 4; + for (int k = 1; k < len; k++) if (!src[i + k] || ((unsigned char)src[i + k] & 0xC0) != 0x80){ len = k; break; } + ltok_push(L, LT_ERR, i, i + len, line, 1); i += len; + } + } + ltok_push(L, LT_EOF, i, i, line, 0); +} +static void lud_lex_free(LLex* L){ free(L->v); free(L->linestart); memset(L, 0, sizeof(*L)); } + +/* ---------- helpers over the token stream --------------------------------*/ +static int ltok_len(const LTok* t){ return t->end - t->start; } +static int ltok_is(const LLex* L, int i, const char* s){ + if (i < 0 || i >= L->n) return 0; + const LTok* t = &L->v[i]; int n = ltok_len(t); + return (int)strlen(s) == n && !strncmp(L->src + t->start, s, n); +} +/* Copy a token's text into a caller buffer; returns buf. */ +static char* ltok_text(const LLex* L, int i, char* buf, int cap){ + const LTok* t = &L->v[i]; int n = ltok_len(t); + if (n >= cap) n = cap - 1; + memcpy(buf, L->src + t->start, n); buf[n] = 0; return buf; +} +/* Index of the next token that is not a newline or comment, or -1. */ +static int ltok_next_sig(const LLex* L, int i){ + for (int j = i + 1; j < L->n; j++){ + int k = L->v[j].kind; + if (k != LT_NL && k != LT_COMMENT) return j; + } + return -1; +} +static int ltok_prev_sig(const LLex* L, int i){ + for (int j = i - 1; j >= 0; j--){ + int k = L->v[j].kind; + if (k != LT_NL && k != LT_COMMENT) return j; + } + return -1; +} +#endif /* LUDIC_SYNTAX_H */ diff --git a/tools/ludic-tools/ludic_workspace.h b/tools/ludic-tools/ludic_workspace.h new file mode 100644 index 00000000..c1a6a855 --- /dev/null +++ b/tools/ludic-tools/ludic_workspace.h @@ -0,0 +1,405 @@ +/* ============================================================================ + * ludic_workspace.h — many documents, one project. + * + * Ludic programs are multi-file: `import "rules.ludic"` splices a fragment into + * whichever `game`/`module` file pulled it in. An imported fragment is NOT a + * standalone program — it has no `game` block — so running the compiler on it + * directly is meaningless. This layer keeps that straight: it knows which files + * form a compilation unit, which file is its root, and it resolves a name + * against the whole unit rather than one buffer. + * ==========================================================================*/ +#ifndef LUDIC_WORKSPACE_H +#define LUDIC_WORKSPACE_H + +#include "ludic_index.h" +#include +#include +#include +#include + +/* ---------- paths & URIs --------------------------------------------------*/ +static char* lw_readfile(const char* path, long* out_n){ + FILE* f = fopen(path, "rb"); if (!f) return 0; + fseek(f, 0, SEEK_END); long n = ftell(f); fseek(f, 0, SEEK_SET); + char* b = malloc(n + 1); + if (fread(b, 1, n, f) != (size_t)n){ fclose(f); free(b); return 0; } + b[n] = 0; fclose(f); + if (out_n) *out_n = n; + return b; +} +static int lw_hex(int c){ return c >= '0' && c <= '9' ? c - '0' : (c | 32) >= 'a' && (c | 32) <= 'f' ? (c | 32) - 'a' + 10 : -1; } +static char* lw_uri_to_path(const char* uri){ + if (strncmp(uri, "file://", 7)) return strdup(uri); + const char* s = uri + 7; + /* file://host/path is not something an editor sends for local files */ + char* out = malloc(strlen(s) + 1); int j = 0; + for (int i = 0; s[i]; ){ + if (s[i] == '%' && lw_hex(s[i+1]) >= 0 && lw_hex(s[i+2]) >= 0){ + out[j++] = (char)(lw_hex(s[i+1]) * 16 + lw_hex(s[i+2])); i += 3; + } else out[j++] = s[i++]; + } + out[j] = 0; + return out; +} +static char* lw_path_to_uri(const char* path){ + static const char* safe = "-_.~/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + size_t cap = strlen(path) * 3 + 16; + char* out = malloc(cap); + strcpy(out, "file://"); + int j = 7; + for (int i = 0; path[i]; i++){ + unsigned char c = (unsigned char)path[i]; + if (strchr(safe, c)) out[j++] = c; + else j += sprintf(out + j, "%%%02X", c); + } + out[j] = 0; + return out; +} +static char* lw_dirname(const char* p){ + char* d = strdup(p); char* s = strrchr(d, '/'); + if (s) *s = 0; else { free(d); d = strdup("."); } + return d; +} +static char* lw_join(const char* dir, const char* rel){ + if (rel[0] == '/') return strdup(rel); + size_t n = strlen(dir) + strlen(rel) + 2; + char* p = malloc(n); snprintf(p, n, "%s/%s", dir, rel); + char real[PATH_MAX]; + if (realpath(p, real)){ free(p); return strdup(real); } + return p; +} +static int lw_ends(const char* s, const char* suf){ + size_t a = strlen(s), b = strlen(suf); + return a >= b && !strcmp(s + a - b, suf); +} + +/* ---------- Markdown ------------------------------------------------------ + * Fenced Ludic inside prose is real Ludic and deserves the same treatment. The + * trick that makes it free: copy the document and blank out every byte that is + * not inside a ```ludic fence. Offsets, lines and columns still match the file + * on disk exactly, so every feature built on top — highlighting, hover, + * go-to-definition, diagnostics — works on a .md without knowing about it. */ +static char* lw_scrub_markdown(const char* src){ + char* out = strdup(src); + int i = 0, n = (int)strlen(src); + while (i < n){ + int ls = i, le = i; + while (le < n && src[le] != '\n') le++; + int ind = 0; while (ls + ind < le && src[ls + ind] == ' ') ind++; + int j = ls + ind; char m = j < le ? src[j] : 0; + int run = 0; while (j + run < le && src[j + run] == m) run++; + int fenced = (m == '`' || m == '~') && run >= 3; + int info = j + run; + int is_ludic = 0; + if (fenced){ + int k = info; while (k < le && (src[k] == ' ' || src[k] == '\t')) k++; + is_ludic = (le - k >= 5) && !strncasecmp(src + k, "ludic", 5) && + (le - k == 5 || src[k+5] == ' ' || src[k+5] == '\t' || src[k+5] == '\r'); + } + /* blank the fence line itself either way */ + for (int k = ls; k < le; k++) out[k] = ' '; + i = le < n ? le + 1 : n; + if (!fenced) continue; + /* inside a fence: keep the body only when the info string says ludic */ + while (i < n){ + int bs = i, be = i; + while (be < n && src[be] != '\n') be++; + int bi = 0; while (bs + bi < be && src[bs + bi] == ' ') bi++; + int cj = bs + bi, crun = 0; + while (cj + crun < be && src[cj + crun] == m) crun++; + int only = 1; + for (int k = cj + crun; k < be; k++) if (src[k] != ' ' && src[k] != '\r'){ only = 0; break; } + if (crun >= run && only){ + for (int k = bs; k < be; k++) out[k] = ' '; + i = be < n ? be + 1 : n; + break; + } + if (!is_ludic) for (int k = bs; k < be; k++) out[k] = ' '; + i = be < n ? be + 1 : n; + } + } + return out; +} + +/* ---------- documents -----------------------------------------------------*/ +static void ldoc_settext(LDoc* D, char* raw){ + if (D->text != D->raw) free(D->text); + free(D->raw); + D->raw = raw; + D->text = D->is_markdown ? lw_scrub_markdown(raw) : raw; +} +static void ldoc_reindex(LDoc* D){ + lud_lex_free(&D->lex); + lud_lex(&D->lex, D->text); + ldoc_match_braces(D); + ldoc_parse(D); + free(D->cls); + D->cls = calloc(D->lex.n + 1, 1); +} +static LDoc* lw_new_doc(const char* path, char* text){ + LDoc* D = calloc(1, sizeof(LDoc)); + char real[PATH_MAX]; + D->path = realpath(path, real) ? strdup(real) : strdup(path); + D->uri = lw_path_to_uri(D->path); + D->is_markdown = lw_ends(D->path, ".md") || lw_ends(D->path, ".markdown"); + ldoc_settext(D, text); + ldoc_reindex(D); + return D; +} +static void lw_add(LIndex* X, LDoc* D){ + if (X->n >= X->cap){ X->cap = X->cap ? X->cap * 2 : 32; X->d = realloc(X->d, X->cap * sizeof(LDoc*)); } + X->d[X->n++] = D; +} +static LDoc* lw_by_path(LIndex* X, const char* path){ + char real[PATH_MAX]; + const char* p = realpath(path, real) ? real : path; + for (int i = 0; i < X->n; i++) if (!strcmp(X->d[i]->path, p)) return X->d[i]; + return 0; +} +static LDoc* lw_by_uri(LIndex* X, const char* uri){ + char* p = lw_uri_to_path(uri); + LDoc* D = lw_by_path(X, p); + if (!D) for (int i = 0; i < X->n; i++) if (!strcmp(X->d[i]->uri, uri)){ D = X->d[i]; break; } + free(p); + return D; +} +/* Load a file into the index if it is not there yet. */ +static LDoc* lw_ensure(LIndex* X, const char* path){ + LDoc* D = lw_by_path(X, path); + if (D) return D; + char* text = lw_readfile(path, 0); + if (!text) return 0; + D = lw_new_doc(path, text); + lw_add(X, D); + return D; +} + +/* Walk the workspace once at startup so that go-to-definition works across + * files the editor has never opened. Skips the usual noise directories. */ +static void lw_scan(LIndex* X, const char* dir, int depth){ + if (depth > 8) return; + DIR* d = opendir(dir); if (!d) return; + struct dirent* e; + while ((e = readdir(d))){ + if (e->d_name[0] == '.') continue; + if (!strcmp(e->d_name, "build") || !strcmp(e->d_name, "node_modules") || + !strcmp(e->d_name, "target") || !strcmp(e->d_name, "out")) continue; + char p[PATH_MAX]; snprintf(p, sizeof(p), "%s/%s", dir, e->d_name); + struct stat st; if (stat(p, &st)) continue; + if (S_ISDIR(st.st_mode)) lw_scan(X, p, depth + 1); + else if (lw_ends(e->d_name, ".ludic")) lw_ensure(X, p); + } + closedir(d); +} + +/* ---------- compilation units -------------------------------------------- + * `related` = every document that shares a compilation unit with D: the unit + * root that (transitively) imports D, plus everything that root imports. */ +static void lw_imports_of(LIndex* X, LDoc* D, LDoc** out, int* n, int max){ + for (int i = 0; i < D->nimport; i++){ + char* dir = lw_dirname(D->path); + char* full = lw_join(dir, D->imports[i]); + free(dir); + LDoc* I = lw_ensure(X, full); + free(full); + if (!I) continue; + int seen = 0; for (int k = 0; k < *n; k++) if (out[k] == I) seen = 1; + if (seen || *n >= max) continue; + out[(*n)++] = I; + lw_imports_of(X, I, out, n, max); + } +} +static int lw_related(LIndex* X, LDoc* D, LDoc** out, int max){ + int n = 0; + if (!D) return 0; + out[n++] = D; + lw_imports_of(X, D, out, &n, max); + /* pull in any unit root that reaches D, and that root's other imports */ + for (int i = 0; i < X->n && n < max; i++){ + LDoc* R = X->d[i]; + if (!R->is_unit || R == D) continue; + LDoc* reach[128]; int rn = 0; + lw_imports_of(X, R, reach, &rn, 128); + int hits = 0; for (int k = 0; k < rn; k++) if (reach[k] == D) hits = 1; + if (!hits) continue; + int seen = 0; for (int k = 0; k < n; k++) if (out[k] == R) seen = 1; + if (!seen && n < max) out[n++] = R; + for (int k = 0; k < rn && n < max; k++){ + int s2 = 0; for (int q = 0; q < n; q++) if (out[q] == reach[k]) s2 = 1; + if (!s2) out[n++] = reach[k]; + } + } + return n; +} +/* The file `ludicc` should actually be pointed at when checking D. */ +static LDoc* lw_unit_root(LIndex* X, LDoc* D){ + if (!D || D->is_markdown) return 0; + if (D->is_unit) return D; + LDoc* rel[128]; int n = lw_related(X, D, rel, 128); + /* a `game` beats a `module`: it is the one that actually compiles */ + for (int i = 0; i < n; i++) if (rel[i]->is_unit && !rel[i]->is_module && !rel[i]->is_markdown) return rel[i]; + for (int i = 0; i < n; i++) if (rel[i]->is_unit && !rel[i]->is_markdown) return rel[i]; + return 0; +} + +/* ---------- name resolution ----------------------------------------------*/ +static int lsym_is_toplevel(int kind){ + switch (kind){ + case LS_COMPONENT: case LS_ARCHETYPE: case LS_CONST: case LS_VAR: + case LS_FN: case LS_EXTERN: case LS_SYSTEM: case LS_UI: case LS_WIDGET: + case LS_SCENE: case LS_LAYER: case LS_UNIT: + return 1; + default: return 0; + } +} +static int lsym_is_local(int kind){ + return kind == LS_LOCAL || kind == LS_PARAM || kind == LS_QUERYVAR || kind == LS_STATE; +} +/* The innermost local binding of `name` visible at byte offset `off`. */ +static int lw_find_local(LDoc* D, const char* name, int off){ + int best = -1; + for (int i = 0; i < D->nsym; i++){ + LSym* s = &D->sym[i]; + if (!lsym_is_local(s->kind) || strcmp(s->name, name)) continue; + if (off < s->body_start || off > s->body_end) continue; + if (best < 0 || s->body_start >= D->sym[best].body_start) best = i; + } + return best; +} +static int lw_find_top(LIndex* X, LDoc* D, const char* name, LDoc** owner){ + LDoc* rel[128]; int n = lw_related(X, D, rel, 128); + for (int i = 0; i < n; i++) + for (int k = 0; k < rel[i]->nsym; k++) + if (lsym_is_toplevel(rel[i]->sym[k].kind) && !strcmp(rel[i]->sym[k].name, name)){ + *owner = rel[i]; return k; + } + /* fall back to the whole workspace — better a cross-unit jump than none */ + for (int i = 0; i < X->n; i++) + for (int k = 0; k < X->d[i]->nsym; k++) + if (lsym_is_toplevel(X->d[i]->sym[k].kind) && !strcmp(X->d[i]->sym[k].name, name)){ + *owner = X->d[i]; return k; + } + return -1; +} +/* The component a dotted receiver has, e.g. `p` in `p.x` when p came from a + * query binding or a typed parameter. Returns the component symbol or -1. */ +static int lw_receiver_component(LIndex* X, LDoc* D, int dot_tok, LDoc** owner){ + int recv = ltok_prev_sig(&D->lex, dot_tok); + if (recv < 0 || D->lex.v[recv].kind != LT_ID) return -1; + char name[96]; ltok_text(&D->lex, recv, name, sizeof(name)); + int l = lw_find_local(D, name, D->lex.v[recv].start); + const char* ty = 0; + if (l >= 0) ty = D->sym[l].type; + else { + LDoc* o; int t = lw_find_top(X, D, name, &o); + if (t >= 0) ty = o->sym[t].type; + } + if (!ty || !ty[0]) return -1; + return lw_find_top(X, D, ty, owner); +} + +/* ---------- semantic classification --------------------------------------*/ +static int lw_first_on_line(LDoc* D, int tok){ + int p = ltok_prev_sig(&D->lex, tok); + return p < 0 || D->lex.v[p].line != D->lex.v[tok].line; +} +static int lw_in_ui_body(LDoc* D, int off){ + for (int i = 0; i < D->nsym; i++) + if (D->sym[i].kind == LS_UI && off > D->sym[i].body_start && off < D->sym[i].body_end) return 1; + return 0; +} +static void lw_classify(LIndex* X, LDoc* D){ + if (!D->cls) D->cls = calloc(D->lex.n + 1, 1); + for (int i = 0; i < D->lex.n; i++){ + const LTok* t = &D->lex.v[i]; + int c = SC_NONE; + switch (t->kind){ + case LT_COMMENT: c = SC_COMMENT; break; + case LT_STR: case LT_CHAR: c = SC_STRING; break; + case LT_INT: case LT_FLOAT: c = SC_NUMBER; break; + case LT_BOOL: case LT_KW: c = SC_KEYWORD; break; + case LT_TYPE: c = SC_TYPE; break; + case LT_PHASE: c = SC_PHASE; break; + case LT_ANNO: c = SC_ANNOTATION; break; + case LT_OP: c = SC_OPERATOR; break; + case LT_ID: c = SC_UNKNOWN; break; + default: c = SC_NONE; break; + } + if (t->kind != LT_ID){ D->cls[i] = (unsigned char)c; continue; } + + char name[96]; ltok_text(&D->lex, i, name, sizeof(name)); + + /* 1. the token IS a declaration's name */ + int decl = -1; + for (int s = 0; s < D->nsym; s++) if (D->sym[s].tok == i){ decl = s; break; } + if (decl >= 0){ + switch (D->sym[decl].kind){ + case LS_COMPONENT: c = SC_COMPONENT; break; + case LS_ARCHETYPE: c = SC_ARCHETYPE; break; + case LS_FIELD: c = SC_FIELD; break; + case LS_CONST: c = SC_CONST; break; + case LS_VAR: c = SC_MODVAR; break; + case LS_FN: case LS_EXTERN: c = SC_FUNCTION; break; + case LS_SYSTEM: c = SC_SYSTEM; break; + case LS_UI: c = SC_UI; break; + case LS_WIDGET: c = SC_CONST; break; /* UI_Foo is a handle */ + case LS_SCENE: c = SC_SCENE; break; + case LS_LAYER: c = SC_LAYER; break; + case LS_PARAM: c = SC_PARAM; break; + case LS_QUERYVAR: case LS_LOCAL: case LS_STATE: c = SC_VARIABLE; break; + case LS_UNIT: c = SC_UI; break; + default: c = SC_UNKNOWN; + } + D->cls[i] = (unsigned char)c; continue; + } + + /* 2. member access: `p.x` */ + int prev = ltok_prev_sig(&D->lex, i); + if (prev >= 0 && ltok_is(&D->lex, prev, ".")){ D->cls[i] = SC_FIELD; continue; } + + int next = ltok_next_sig(&D->lex, i); + int followed_by_eq = next >= 0 && ltok_is(&D->lex, next, "="); + + /* 3. inside a `ui` block a bare word is a widget type and `k=` a prop — + * and those names (text, image, size) collide with builtins, so this + * has to be decided before the builtin table is consulted. */ + if (lw_in_ui_body(D, t->start)){ + if (followed_by_eq){ D->cls[i] = SC_PROP; continue; } + if (lw_first_on_line(D, i) || (prev >= 0 && (ltok_is(&D->lex, prev, "{") || ltok_is(&D->lex, prev, "}")))){ + D->cls[i] = lud_in(LUDIC_WIDGETS, name) ? SC_WIDGET : SC_UI; continue; + } + } + + /* 4. a local binding in scope */ + int l = lw_find_local(D, name, t->start); + if (l >= 0){ D->cls[i] = D->sym[l].kind == LS_PARAM ? SC_PARAM : SC_VARIABLE; continue; } + + /* 5. a declaration somewhere in the compilation unit */ + LDoc* owner = 0; int top = lw_find_top(X, D, name, &owner); + if (top >= 0){ + switch (owner->sym[top].kind){ + case LS_COMPONENT: c = SC_COMPONENT; break; + case LS_ARCHETYPE: c = SC_ARCHETYPE; break; + case LS_CONST: c = SC_CONST; break; + case LS_VAR: c = SC_MODVAR; break; + case LS_FN: case LS_EXTERN: c = SC_FUNCTION; break; + case LS_SYSTEM: c = SC_SYSTEM; break; + case LS_UI: c = SC_UI; break; + case LS_WIDGET: c = SC_CONST; break; + case LS_SCENE: c = SC_SCENE; break; + case LS_LAYER: c = SC_LAYER; break; + default: c = SC_UNKNOWN; + } + D->cls[i] = (unsigned char)c; continue; + } + + /* 6. the runtime surface */ + if (lud_lookup(LUDIC_BUILTINS, name) || lud_lookup(LUDIC_INTRINSICS, name)){ D->cls[i] = SC_BUILTIN; continue; } + + /* 7. a record field initialiser: `Pos = { x = 10 }` */ + if (followed_by_eq){ D->cls[i] = SC_FIELD; continue; } + + D->cls[i] = SC_UNKNOWN; + } +} +#endif /* LUDIC_WORKSPACE_H */ diff --git a/tools/ludic-web/run.mjs b/tools/ludic-web/run.mjs new file mode 100644 index 00000000..3bc0d3e3 --- /dev/null +++ b/tools/ludic-web/run.mjs @@ -0,0 +1,106 @@ +// ============================================================================ +// tools/ludic-web/run.mjs — run a headless Ludic wasm build under Node. +// +// node tools/ludic-web/run.mjs build/web/snake_headless.wasm --stdin=ddss +// +// The point of this runner is the regression it makes possible: the same game, +// the same input, compiled once for the host and once for wasm32, has to render +// the same frame. Ludic is fixed-point and its RNG is seeded, so "the same" here +// means byte-identical PPM — which is a much stronger check on the wasm backend +// than "it started". +// +// It shares runtime/web/platform.js's Host: files, stdin, stdout and the clock +// are identical services whichever host provides them. Only the window differs, +// and a headless build has none. +// ============================================================================ +import { readFileSync, writeFileSync, existsSync } from 'node:fs'; +import { Host, ExitSignal } from '../../runtime/web/platform.js'; + +const args = process.argv.slice(2); +const modulePath = args.find((a) => !a.startsWith('--')); +const stdin = (args.find((a) => a.startsWith('--stdin=')) || '--stdin=').slice(8); +const maxFrames = Number((args.find((a) => a.startsWith('--frames=')) || '--frames=100000').slice(9)); + +if (!modulePath) { + console.error('usage: run.mjs [--stdin=keys] [--frames=n]'); + process.exit(2); +} + +// Files, backed by the real filesystem: a headless build reads its assets and +// writes out.ppm exactly where the native headless binary does. +class NodeFiles { + constructor() { this.open = new Map(); this.next = 1; } + + fopen(path, mode) { + const h = this.next++; + if (mode.includes('w') || mode.includes('a')) { + this.open.set(h, { path, write: true, chunks: [], size: 0, pos: 0 }); + return h; + } + if (!existsSync(path)) return 0; + this.open.set(h, { path, write: false, data: new Uint8Array(readFileSync(path)), pos: 0 }); + return h; + } + + fread(h, dst, want) { + const f = this.open.get(h); + if (!f || f.write) return 0; + const n = Math.max(0, Math.min(want, f.data.length - f.pos)); + dst.set(f.data.subarray(f.pos, f.pos + n)); + f.pos += n; + return n; + } + + fwrite(h, src, n) { + const f = this.open.get(h); + if (!f || !f.write) return 0; + f.chunks.push(src.slice(0, n)); + f.size += n; f.pos += n; + return n; + } + + fclose(h) { + const f = this.open.get(h); + if (!f) return; + if (f.write) { + const all = new Uint8Array(f.size); + let at = 0; + for (const c of f.chunks) { all.set(c, at); at += c.length; } + writeFileSync(f.path, all); + } + this.open.delete(h); + } + + fseek(h, off, whence) { + const f = this.open.get(h); + if (!f) return -1; + const end = f.write ? f.size : f.data.length; + const base = whence === 1 ? f.pos : whence === 2 ? end : 0; + f.pos = Math.max(0, Math.min(end, base + off)); + return 0; + } + + ftell(h) { const f = this.open.get(h); return f ? f.pos : -1; } +} + +const host = new Host({ files: new NodeFiles(), stdin }); +const { instance } = await WebAssembly.instantiate(readFileSync(modulePath), { env: host.imports() }); +host.bind(instance.exports.memory); + +const { ludic_boot, ludic_frame, ludic_alive, ludic_teardown } = instance.exports; + +let frames = 0; +try { + ludic_boot(); + while (host.running && ludic_alive() && frames < maxFrames) { ludic_frame(); frames++; } + ludic_teardown(); +} catch (e) { + if (!(e instanceof ExitSignal)) throw e; +} +host.flush(); + +if (frames >= maxFrames) { + console.error(`ludic-web: stopped after ${maxFrames} frames (the game never ended)`); + process.exit(1); +} +process.exit(host.exitCode ?? 0); diff --git a/tools/test-grammar.js b/tools/test-grammar.js new file mode 100644 index 00000000..97ad2a46 --- /dev/null +++ b/tools/test-grammar.js @@ -0,0 +1,168 @@ +/* ============================================================================ + * test-grammar.js — tokenise Ludic with the real TextMate engine. + * + * A TextMate grammar is a pile of Oniguruma regexes in a JSON file: nothing + * validates it, and a broken pattern shows up as "that word stopped being + * coloured" months later. This runs the grammar through vscode-textmate, the + * same engine VS Code uses, and asserts that specific spans get specific + * scopes — including a ```ludic fence inside Markdown, which is the part most + * likely to break silently. + * + * node tools/test-grammar.js + * + * Needs vscode-textmate and vscode-oniguruma; skips cleanly when they are not + * installed, so it never blocks the suite on a machine without npm. + * ==========================================================================*/ +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.dirname(__dirname); +const SHARED = path.join(ROOT, 'tools', 'editors', 'shared'); + +let vsctm, oniguruma; +try { + const local = path.join(ROOT, 'tools', 'editors', 'vscode', 'node_modules'); + const paths = [local, '/tmp/tmgrammar/node_modules', ...module.paths]; + vsctm = require(require.resolve('vscode-textmate', { paths })); + oniguruma = require(require.resolve('vscode-oniguruma', { paths })); +} catch (e) { + console.log(' skip TextMate grammar (npm i vscode-textmate vscode-oniguruma to run)'); + process.exit(0); +} + +let passed = 0; +let failed = 0; + +function ok(name) { passed++; console.log(` ok ${name}`); } +function bad(name, detail) { failed++; console.log(` FAIL ${name}\n ${detail}`); } + +async function main() { + const wasmPath = require.resolve('vscode-oniguruma/release/onig.wasm', { + paths: [path.join(ROOT, 'tools', 'editors', 'vscode', 'node_modules'), '/tmp/tmgrammar/node_modules'] + }); + await oniguruma.loadWASM(fs.readFileSync(wasmPath).buffer); + + const onigLib = Promise.resolve({ + createOnigScanner: (sources) => new oniguruma.OnigScanner(sources), + createOnigString: (s) => new oniguruma.OnigString(s) + }); + + const grammars = { + 'source.ludic': path.join(SHARED, 'ludic.tmLanguage.json'), + 'markdown.ludic.codeblock': path.join(SHARED, 'ludic.markdown-injection.json') + }; + + const registry = new vsctm.Registry({ + onigLib, + loadGrammar: (scope) => { + const file = grammars[scope]; + if (!file) return Promise.resolve(null); + return Promise.resolve(vsctm.parseRawGrammar(fs.readFileSync(file, 'utf8'), file)); + }, + getInjections: (scope) => + scope === 'text.html.markdown' || scope.startsWith('text.html.markdown') + ? ['markdown.ludic.codeblock'] + : undefined + }); + + const grammar = await registry.loadGrammar('source.ludic'); + if (!grammar) { + bad('grammar loads', 'registry returned null'); + return report(); + } + ok('grammar loads without a regex error'); + + // Tokenise a line and return the scopes covering the first occurrence of a + // substring, so assertions read in terms of the source rather than offsets. + function scopesFor(line, needle, state = vsctm.INITIAL) { + const at = line.indexOf(needle); + if (at < 0) throw new Error(`${needle} not in ${line}`); + const result = grammar.tokenizeLine(line, state); + for (const t of result.tokens) { + if (t.startIndex <= at && at < t.endIndex) return t.scopes; + } + return []; + } + function has(scopes, prefix) { return scopes.some((s) => s.startsWith(prefix)); } + + function expect(name, line, needle, prefix) { + try { + const scopes = scopesFor(line, needle); + if (has(scopes, prefix)) ok(name); + else bad(name, `${needle!== undefined ? JSON.stringify(needle) : ''} got [${scopes.join(' ')}], wanted ${prefix}`); + } catch (e) { + bad(name, e.message); + } + } + + expect('comment', '# a note', '# a note', 'comment.line'); + expect('string', 'const S: str = "hi"', '"hi"', 'string.quoted.double'); + expect('hex literal', 'clear(0x0e0e16)', '0x0e0e16', 'constant.numeric.hex'); + expect('fixed literal', 'let f = 1.5', '1.5', 'constant.numeric.fixed'); + expect('declaration keyword', 'component Pos { x: int = 0 }', 'component', 'storage.type.component'); + expect('component name', 'component Pos { x: int = 0 }', 'Pos', 'entity.name.type.component'); + expect('primitive type', 'component Pos { x: int = 0 }', 'int', 'support.type.primitive'); + expect('system name', 'system Move phase Update {', 'Move', 'entity.name.function.system'); + expect('phase name', 'system Move phase Update {', 'Update', 'constant.language.phase'); + expect('clause keyword', ' reads [Vel]', 'reads', 'keyword.other.clause'); + expect('annotation', 'system Move @deterministic', '@deterministic', 'entity.name.function.decorator'); + expect('builtin call', ' clear(0x000000)', 'clear', 'support.function.builtin'); + expect('intrinsic call', ' mem_alloc(64)', 'mem_alloc', 'support.function.intrinsic'); + expect('control keyword', ' if a == 1 { }', 'if', 'keyword.control'); + expect('member access', ' p.x = 1', 'x', 'variable.other.property'); + expect('query tag filter', 'for (p) in query [Pos, {Player}] {', 'Player', 'entity.name.type.tag'); + expect('query component', 'for (p) in query [Pos, {Player}] {', 'Pos', 'entity.name.type.component'); + expect('widget type', ' button id=Go text="go"', 'button', 'support.class.widget'); + expect('widget prop', ' button id=Go text="go"', 'id', 'variable.parameter.widget'); + expect('user function call', ' my_helper(1)', 'my_helper', 'entity.name.function'); + expect('archetype in spawn', ' spawn Hero {', 'Hero', 'entity.name.type.archetype'); + expect('scene in enter', ' enter Battle', 'Battle', 'entity.name.type.scene'); + + // A whole file must tokenise without the engine bailing out. + const sample = fs.readFileSync(path.join(ROOT, 'examples', 'menu.ludic'), 'utf8'); + let state = vsctm.INITIAL; + let tokenCount = 0; + for (const line of sample.split('\n')) { + const r = grammar.tokenizeLine(line, state); + state = r.ruleStack; + tokenCount += r.tokens.length; + } + if (tokenCount > 200) ok(`tokenises examples/menu.ludic (${tokenCount} tokens)`); + else bad('tokenises examples/menu.ludic', `only ${tokenCount} tokens`); + + // ---- the Markdown injection --------------------------------------------- + const mdGrammar = await registry.loadGrammar('markdown.ludic.codeblock'); + if (!mdGrammar) { + bad('markdown injection grammar loads', 'registry returned null'); + return report(); + } + ok('markdown injection grammar loads without a regex error'); + + // Drive the injection directly: feed it the fence, then the body, and check + // the body is handed to source.ludic. + const lines = ['```ludic', 'component Pos { x: int = 0 }', '```']; + let mdState = vsctm.INITIAL; + const bodyScopes = []; + lines.forEach((line, i) => { + const r = mdGrammar.tokenizeLine(line, mdState); + mdState = r.ruleStack; + if (i === 1) for (const t of r.tokens) bodyScopes.push(t.scopes.join(' ')); + }); + const joined = bodyScopes.join(' | '); + if (joined.includes('meta.embedded.block.ludic')) ok('markdown fence body is embedded as Ludic'); + else bad('markdown fence body is embedded as Ludic', joined || '(no tokens)'); + if (joined.includes('storage.type.component')) ok('markdown fence body is highlighted by source.ludic'); + else bad('markdown fence body is highlighted by source.ludic', joined || '(no tokens)'); + + report(); +} + +function report() { + console.log(` ${passed} passed, ${failed} failed`); + process.exit(failed ? 1 : 0); +} + +main().catch((e) => { + console.log(` FAIL grammar test crashed\n ${e.stack}`); + process.exit(1); +}); diff --git a/tools/test-lsp.py b/tools/test-lsp.py new file mode 100755 index 00000000..012c194c --- /dev/null +++ b/tools/test-lsp.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python3 +"""Drive build/ludic-lsp over real LSP traffic against the real source tree. + +Every assertion here is about a feature an editor actually calls: if this +passes, VS Code, JetBrains, Neovim and the rest are exercising code paths that +have been checked, because they all speak to this one binary. +""" +import json +import os +import subprocess +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SERVER = os.path.join(ROOT, "build", "ludic-lsp") + +passed = 0 +failed = 0 + + +def check(name, got, want): + global passed, failed + if got == want: + passed += 1 + print(f" ok {name}") + else: + failed += 1 + print(f" FAIL {name}\n expected {want!r}, got {got!r}") + + +def check_true(name, cond, detail=""): + check(name, bool(cond), True) if cond else check(name + (f" ({detail})" if detail else ""), False, True) + + +class Client: + def __init__(self, cwd): + self.p = subprocess.Popen([SERVER], stdin=subprocess.PIPE, + stdout=subprocess.PIPE, cwd=cwd) + self.diagnostics = {} + + def _send(self, obj): + body = json.dumps(obj).encode() + self.p.stdin.write(b"Content-Length: %d\r\n\r\n" % len(body) + body) + self.p.stdin.flush() + + def _read(self): + header = b"" + while not header.endswith(b"\r\n\r\n"): + c = self.p.stdout.read(1) + if not c: + return None + header += c + length = int([l for l in header.decode().split("\r\n") + if l.lower().startswith("content-length")][0].split(":")[1]) + return json.loads(self.p.stdout.read(length)) + + def request(self, method, params, _id=[0]): + _id[0] += 1 + rid = _id[0] + self._send({"jsonrpc": "2.0", "id": rid, "method": method, "params": params}) + while True: + msg = self._read() + if msg is None: + raise RuntimeError(f"server closed during {method}") + if msg.get("id") == rid: + return msg.get("result") + if msg.get("method") == "textDocument/publishDiagnostics": + p = msg["params"] + self.diagnostics[os.path.basename(p["uri"])] = [d["message"] for d in p["diagnostics"]] + + def notify(self, method, params): + self._send({"jsonrpc": "2.0", "method": method, "params": params}) + + def open(self, path, language_id="ludic"): + with open(path) as fh: + text = fh.read() + self.notify("textDocument/didOpen", {"textDocument": { + "uri": "file://" + path, "languageId": language_id, "version": 1, "text": text}}) + return text + + def close(self): + try: + self.request("shutdown", None) + self.notify("exit", None) + except Exception: + pass + self.p.kill() + + +def position_of(text, needle, offset=0): + for i, line in enumerate(text.split("\n")): + if needle in line: + return {"line": i, "character": line.index(needle) + offset} + raise AssertionError(f"{needle!r} not found") + + +def main(): + if not os.access(SERVER, os.X_OK): + print(" skip ludic-lsp missing") + return 2 + + c = Client(ROOT) + caps = c.request("initialize", {"rootUri": "file://" + ROOT, "capabilities": {}})["capabilities"] + c.notify("initialized", {}) + + for cap in ["completionProvider", "hoverProvider", "definitionProvider", + "referencesProvider", "renameProvider", "documentSymbolProvider", + "workspaceSymbolProvider", "documentFormattingProvider", + "semanticTokensProvider", "foldingRangeProvider", + "signatureHelpProvider", "inlayHintProvider", "documentLinkProvider"]: + check_true(f"advertises {cap}", cap in caps) + + # ---- a fragment file: no `game` block, only reachable through an import -- + frag = os.path.join(ROOT, "examples/chronorift/combat.ludic") + text = c.open(frag) + uri = {"uri": "file://" + frag} + + syms = c.request("textDocument/documentSymbol", {"textDocument": uri}) + check_true("document symbols in an imported fragment", len(syms) >= 3) + + # a field reached through a query binding, declared in ANOTHER file + pos = position_of(text, "st.guard", 3) + hov = c.request("textDocument/hover", {"textDocument": uri, "position": pos}) + check_true("hover resolves a field through a query binding", + hov and "Stats.guard: int" in hov["contents"]["value"]) + + d = c.request("textDocument/definition", {"textDocument": uri, "position": pos}) + check_true("go-to-definition crosses files", d and d["uri"].endswith("world.ludic")) + + # a binding is not yet inside its own scope at the point it is written, so + # resolving it has to go through the declaration table, not scope lookup + qpos = position_of(text, "for (e) in query", 5) + qhov = c.request("textDocument/hover", {"textDocument": uri, "position": qpos}) + check_true("hover works on a query binding at its declaration site", + qhov and "query binding" in qhov["contents"]["value"], + json.dumps(qhov)[:80]) + + comp = c.request("textDocument/completion", {"textDocument": uri, + "position": position_of(text, "st.guard", 3)}) + labels = [i["label"] for i in comp["items"]] + check_true("completion after '.' offers only that component's fields", + "guard" in labels and "hp" in labels and "clear" not in labels) + + # a query's term list admits components and archetypes and nothing else — + # not the loop variables, not builtins, not keywords + qsrc = ('game QT {\n component Pos { x: int = 0 }\n component Vel { dx: int = 0 }\n' + ' system S phase Update {\n for (a, b) in query [Pos, ] { }\n }\n}\n') + qfile = "/tmp/ludic_lsp_test_query.ludic" + with open(qfile, "w") as fh: + fh.write(qsrc) + c.open(qfile) + quri = {"uri": "file://" + qfile} + qcomp = c.request("textDocument/completion", + {"textDocument": quri, "position": position_of(qsrc, "[Pos, ]", 6)}) + qlabels = sorted(i["label"] for i in qcomp["items"]) + check("completion inside query terms lists components only", qlabels, ["Pos", "Vel"]) + body = c.request("textDocument/completion", + {"textDocument": quri, "position": position_of(qsrc, "] { }", 3)}) + blabels = [i["label"] for i in body["items"]] + check_true("completion in the loop body still has locals and builtins", + "a" in blabels and "clear" in blabels) + os.unlink(qfile) + + refs = c.request("textDocument/references", {"textDocument": uri, + "position": position_of(text, "query [Stats", 7), + "context": {"includeDeclaration": True}}) + files = {os.path.basename(r["uri"]) for r in refs} + check_true("find-usages spans the compilation unit", len(files) >= 3, str(sorted(files))) + + hints = c.request("textDocument/inlayHint", {"textDocument": uri, + "range": {"start": {"line": 0, "character": 0}, + "end": {"line": 9999, "character": 0}}}) + check_true("inlay hints name query binding types", any(": Stats" == h["label"] for h in hints)) + + sig = c.request("textDocument/signatureHelp", + {"textDocument": uri, "position": position_of(text, "rng_chance(", 11)}) + check_true("signature help for a builtin", + sig and sig["signatures"][0]["label"].startswith("rng_chance(")) + + toks = c.request("textDocument/semanticTokens/full", {"textDocument": uri}) + check_true("semantic tokens produced", len(toks["data"]) // 5 > 100) + check_true("semantic token stream is well formed", len(toks["data"]) % 5 == 0) + + folds = c.request("textDocument/foldingRange", {"textDocument": uri}) + check_true("folding ranges produced", len(folds) > 5) + + # ---- structural diagnostics arrive while typing -------------------------- + c.notify("textDocument/didChange", {"textDocument": {"uri": uri["uri"], "version": 2}, + "contentChanges": [{"text": text + "\n{ oops"}]}) + c.request("textDocument/documentSymbol", {"textDocument": uri}) + check_true("unbalanced brace reported while typing", + any("unclosed" in m for m in c.diagnostics.get("combat.ludic", []))) + + # ---- the LSP analyses opened files on its own ---------------------------- + # (Deep semantic diagnostics once came from `ludicc --fmt`; the compiler is + # now written in Ludic and the LSP relies on its own parser. It still opens + # any file and answers structural queries without a compiler present.) + bad = "/tmp/ludic_lsp_test_bad.ludic" + with open(bad, "w") as fh: + fh.write("game Bad {\n component P { x: nosuchtype = 0 }\n}\n") + c.open(bad) + syms = c.request("textDocument/documentSymbol", {"textDocument": {"uri": "file://" + bad}}) + check_true("LSP opens and analyses a file with no compiler present", + any(s["name"] == "Bad" for s in syms)) + os.unlink(bad) + + # ---- markdown: ```ludic fences are real Ludic --------------------------- + md = "/tmp/ludic_lsp_test.md" + with open(md, "w") as fh: + fh.write("# Title\n\nprose\n\n```ludic\ngame D { component Pt { x: int = 0 } }\n```\n\n" + "```python\nz = 1\n```\n") + c.open(md, "markdown") + mduri = {"uri": "file://" + md} + mdsyms = c.request("textDocument/documentSymbol", {"textDocument": mduri}) + check_true("symbols found inside a markdown fence", [s["name"] for s in mdsyms] == ["D"]) + mdtoks = c.request("textDocument/semanticTokens/full", {"textDocument": mduri}) + check("markdown tokens start on the fence body line", mdtoks["data"][0], 5) + # A fence is a snippet: elisions and half-shown blocks are the documentation + # doing its job, so errors there would be noise. Highlighting still applies. + check("no diagnostics are reported for markdown", c.diagnostics.get("ludic_lsp_test.md"), []) + fmt = c.request("textDocument/formatting", {"textDocument": mduri, + "options": {"tabSize": 2, "insertSpaces": True}}) + check_true("markdown formatting leaves prose and other fences alone", + "prose" in fmt[0]["newText"] and "z = 1" in fmt[0]["newText"]) + os.unlink(md) + + # the repository's own documentation must not light up with false errors + for doc in ("LANGUAGE.md", "README.md", "COMPILING.md"): + path = os.path.join(ROOT, doc) + if not os.path.exists(path): + continue + c.open(path, "markdown") + c.request("textDocument/documentSymbol", {"textDocument": {"uri": "file://" + path}}) + check(f"{doc} opens with no diagnostics", c.diagnostics.get(doc, []), []) + lang = os.path.join(ROOT, "LANGUAGE.md") + if os.path.exists(lang): + t = c.request("textDocument/semanticTokens/full", {"textDocument": {"uri": "file://" + lang}}) + check_true("LANGUAGE.md fences are highlighted", len(t["data"]) // 5 > 100) + + # ---- rename has to be resolution-based, not textual ---------------------- + # `x` here is a field of Pos, a field of Vel, a local, and a parameter. + # Renaming any one of them must leave the other three alone. + amb = "/tmp/ludic_lsp_test_rename.ludic" + with open(amb, "w") as fh: + fh.write("game R {\n" + " component Pos { x: int = 0, y: int = 0 }\n" + " component Vel { x: int = 0 }\n" + " fn helper(x: int) -> int { return x + 1 }\n" + " system A phase Update {\n" + " for (p) in query [Pos] {\n" + " let x = 5\n" + " p.x = p.x + x\n" + " }\n" + " }\n" + " system B phase Update {\n" + " for (v) in query [Vel] { v.x = v.x + 1 }\n" + " }\n" + "}\n") + atext = c.open(amb) + auri = {"uri": "file://" + amb} + + def rename_at(pos): + r = c.request("textDocument/rename", + {"textDocument": auri, "position": pos, "newName": "ZZZ"}) + if not r or not r.get("changes"): + return [] + return list(r["changes"].values())[0] + + def lines_touched(edits): + return sorted({e["range"]["start"]["line"] for e in edits}) + + field = rename_at(position_of(atext, "component Pos { x", 16)) + check("renaming Pos.x touches only its declaration and its uses", + lines_touched(field), [1, 7]) + local = rename_at(position_of(atext, "let x = 5", 4)) + check("renaming a local touches only that local", lines_touched(local), [6, 7]) + param = rename_at(position_of(atext, "fn helper(x", 10)) + check("renaming a parameter touches only that function", lines_touched(param), [3]) + check("renaming a parameter makes exactly two edits", len(param), 2) + + # find-usages must be equally precise + refs_x = c.request("textDocument/references", + {"textDocument": auri, + "position": position_of(atext, "component Vel { x", 16), + "context": {"includeDeclaration": True}}) + check("find-usages of Vel.x does not pick up Pos.x", + sorted({r["range"]["start"]["line"] for r in refs_x}), [2, 11]) + os.unlink(amb) + + # ---- workspace-wide symbol search --------------------------------------- + ws = c.request("workspace/symbol", {"query": "Stats"}) + check_true("workspace symbol search finds a component", any(s["name"] == "Stats" for s in ws)) + + c.close() + print(f" {passed} passed, {failed} failed") + return 1 if failed else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/test-tools.sh b/tools/test-tools.sh new file mode 100755 index 00000000..d4acdd56 --- /dev/null +++ b/tools/test-tools.sh @@ -0,0 +1,198 @@ +#!/bin/bash +# test-tools.sh — regression suite for the Ludic editor toolchain. +# +# The two properties that matter most are checked against the real source tree +# rather than toy inputs: +# +# 1. the formatter is a no-op on already-formatted code, and idempotent; +# 2. formatting never changes the program — proved by comparing the +# COMPILER's own canonical AST dump before and after. +# +# Then the language server is driven over real LSP traffic on real files. +set -u +cd "$(dirname "$0")/.." + +FMT=build/ludic-fmt +LSP=build/ludic-lsp +LUDICC=build/ludicc +PASS=0 +FAIL=0 +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +ok() { PASS=$((PASS+1)); printf ' ok %s\n' "$1"; } +bad() { FAIL=$((FAIL+1)); printf ' FAIL %s\n' "$1"; [ $# -gt 1 ] && printf ' %s\n' "$2"; } +check() { if [ "$2" = "$3" ]; then ok "$1"; else bad "$1" "expected [$3] got [$2]"; fi; } + +[ -x "$FMT" ] || { echo "build/ludic-fmt missing — run ./tools/build-tools.sh"; exit 2; } +[ -x "$LSP" ] || { echo "build/ludic-lsp missing — run ./tools/build-tools.sh"; exit 2; } + +SOURCES=$(find examples runtime -name '*.ludic' | sort) + +echo "formatter" + +# --- idempotence: formatting twice equals formatting once ------------------- +for f in $SOURCES; do + "$FMT" "$f" > "$TMP/a" 2>/dev/null + "$FMT" "$TMP/a" > "$TMP/b" 2>/dev/null + if ! cmp -s "$TMP/a" "$TMP/b"; then bad "idempotent: $f"; fi +done +[ $FAIL -eq 0 ] && ok "idempotent on $(echo "$SOURCES" | wc -l | tr -d ' ') files" + +# --- meaning preserved: reformatting a formatted file must be a no-op -------- +# (The compiler is now written in Ludic and has no --fmt AST-dump mode, so the +# formatter is validated by its own idempotence rather than against ludicc.) +MISMATCH="" +for f in examples/hello.ludic examples/snake.ludic examples/menu.ludic \ + examples/qdecl.ludic examples/scenes.ludic; do + [ -f "$f" ] || continue + "$FMT" "$f" > "$TMP/f1.ludic" + "$FMT" "$TMP/f1.ludic" > "$TMP/f2.ludic" + cmp -s "$TMP/f1.ludic" "$TMP/f2.ludic" || MISMATCH="$MISMATCH $f" +done +if [ -z "$MISMATCH" ]; then ok "formatting is idempotent (fmt(fmt(x)) == fmt(x))" +else bad "formatting is not idempotent" "$MISMATCH"; fi + +# --- the strongest invariant: only whitespace ever changes ----------------- +# Every token is re-emitted in order, so stripping whitespace from the input and +# from the output must give identical bytes. This is what makes the formatter +# safe to run on save: it cannot lose, reorder or corrupt anything. +DRIFT="" +for f in $SOURCES README.md LANGUAGE.md COMPILING.md; do + [ -f "$f" ] || continue + "$FMT" "$f" > "$TMP/f" 2>/dev/null + a=$(tr -d ' \t\n' < "$f" | shasum | cut -d' ' -f1) + b=$(tr -d ' \t\n' < "$TMP/f" | shasum | cut -d' ' -f1) + [ "$a" = "$b" ] || DRIFT="$DRIFT $f" +done +if [ -z "$DRIFT" ]; then ok "only whitespace changes (byte-identical modulo spacing)" +else bad "formatter altered non-whitespace bytes" "$DRIFT"; fi + +# --- multi-byte characters must survive intact ------------------------------ +# A UTF-8 character outside a string is an error to the compiler, but the +# formatter must still not split it: doing so silently corrupts the file. +printf 'game E {\n # \xe2\x80\xa6 ellipsis in a comment\n const S: str = "caf\xc3\xa9 \xe2\x86\x92 na\xc3\xafve"\n}\n' > "$TMP/utf8.ludic" +"$FMT" "$TMP/utf8.ludic" > "$TMP/utf8.out" +if cmp -s "$TMP/utf8.ludic" "$TMP/utf8.out"; then ok "UTF-8 preserved byte for byte" +else bad "UTF-8 mangled" "$(diff "$TMP/utf8.ludic" "$TMP/utf8.out" | head -2)"; fi +# the same character where the compiler cannot make sense of it at all: it must +# still come out as one character, not as three spaced-out replacement bytes +printf 'game F {\nfn f() -> int { return \xe2\x80\xa6 }\n}\n' > "$TMP/utf8b.ludic" +a=$(tr -d ' \t\n' < "$TMP/utf8b.ludic" | shasum | cut -d' ' -f1) +b=$("$FMT" "$TMP/utf8b.ludic" | tr -d ' \t\n' | shasum | cut -d' ' -f1) +check "unrecognised characters pass through whole" "$b" "$a" + +# --- comments survive, which is the whole reason this is not ludicc --fmt --- +printf 'game C {\n # keep me\n component P { x: int = 0 } # and me\n}\n' > "$TMP/c.ludic" +N=$("$FMT" "$TMP/c.ludic" | grep -c '#') +check "comments preserved" "$N" "2" + +# --- messy input is normalised ---------------------------------------------- +printf 'game M{\ncomponent P{x:int=0}\nsystem S phase Update{let a=1+2\nif a== -1 {a=-a}}\n}\n' > "$TMP/m.ludic" +"$FMT" "$TMP/m.ludic" > "$TMP/m.out" +grep -q '^ component P { x: int = 0 }$' "$TMP/m.out" && ok "reindents and respaces" || bad "reindents and respaces" +grep -q 'a = -a' "$TMP/m.out" && ok "unary minus not spaced" || bad "unary minus not spaced" + +# --- language conventions are respected, not overwritten -------------------- +printf 'game U {\n ui M {\n panel id=Root w=10 {\n button id=Go text="go"\n }\n }\n}\n' > "$TMP/u.ludic" +"$FMT" "$TMP/u.ludic" | grep -q 'id=Root' && ok "widget props stay tight (id=Root)" || bad "widget props stay tight" +printf 'game Q {\n system S phase Update {\n for (p) in query [Pos, {Foe}] { }\n }\n component Pos { x: int = 0 }\n component Foe { }\n}\n' > "$TMP/q.ludic" +"$FMT" "$TMP/q.ludic" | grep -q '\[Pos, {Foe}\]' && ok "query tags stay tight ({Foe})" || bad "query tags stay tight" +printf 'game A {\n const R_A: int = 0 # one\n const R_BBB: int = 1 # two\n}\n' > "$TMP/a.ludic" +"$FMT" "$TMP/a.ludic" | grep -q 'R_A: int = 0 # one' && ok "hand alignment preserved" || bad "hand alignment preserved" + +# --- --check exit status, for CI and pre-commit hooks ----------------------- +"$FMT" --check -q "$TMP/m.ludic" >/dev/null 2>&1 +check "--check exits 1 on unformatted input" "$?" "1" +"$FMT" -w "$TMP/m.ludic" >/dev/null 2>&1 +"$FMT" --check -q "$TMP/m.ludic" >/dev/null 2>&1 +check "--check exits 0 after -w" "$?" "0" + +# --- markdown: fences formatted, prose untouched ---------------------------- +printf '# T\n\nprose with spaces\n\n```ludic\ngame D{component P{x:int=0}}\n```\n\n```python\nz = 1\n```\n' > "$TMP/d.md" +"$FMT" "$TMP/d.md" > "$TMP/d.out" +grep -q 'prose with spaces' "$TMP/d.out" && ok "markdown prose untouched" || bad "markdown prose untouched" +grep -q 'z = 1' "$TMP/d.out" && ok "non-ludic fences untouched" || bad "non-ludic fences untouched" +grep -q 'game D { component P { x: int = 0 } }' "$TMP/d.out" && ok "ludic fences formatted" || bad "ludic fences formatted" + +echo "language server" +python3 tools/test-lsp.py +LSPRC=$? +if [ $LSPRC -eq 0 ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); fi + +echo +echo "editor assets" +for f in tools/editors/shared/ludic.tmLanguage.json \ + tools/editors/shared/ludic.markdown-injection.json \ + tools/editors/shared/language-configuration.json \ + tools/editors/vscode/package.json \ + tools/editors/vscode/snippets/ludic.json; do + if python3 -c "import json,sys;json.load(open(sys.argv[1]))" "$f" 2>/dev/null; then ok "valid JSON: $(basename "$f")" + else bad "invalid JSON: $f"; fi +done +for f in tools/editors/jetbrains/src/main/resources/META-INF/plugin.xml \ + tools/editors/jetbrains/src/main/resources/META-INF/ludic-markdown.xml; do + if python3 -c "import xml.dom.minidom,sys;xml.dom.minidom.parse(sys.argv[1])" "$f" 2>/dev/null; then ok "valid XML: $(basename "$f")" + else bad "invalid XML: $f"; fi +done +if command -v node >/dev/null 2>&1; then + node --check tools/editors/vscode/src/extension.js 2>/dev/null && ok "extension.js parses" || bad "extension.js parses" + # A TextMate grammar is unvalidated JSON full of regexes; run it through the + # engine VS Code actually uses rather than assuming it still works. + echo "textmate grammar" + node tools/test-grammar.js + if [ $? -eq 0 ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); fi +else + echo " skip extension.js and grammar tests (node not installed)" +fi + +# VS Code carries its own copy of the shared grammar because an extension must +# be self-contained. build-tools.sh refreshes it; this catches an edit made to +# the copy instead of the original. +SYNCED=1 +for f in ludic.tmLanguage.json ludic.markdown-injection.json; do + cmp -s "tools/editors/shared/$f" "tools/editors/vscode/syntaxes/$f" || SYNCED=0 +done +cmp -s tools/editors/shared/language-configuration.json tools/editors/vscode/language-configuration.json || SYNCED=0 +if [ $SYNCED -eq 1 ]; then ok "vscode grammar copies match tools/editors/shared" +else bad "vscode grammar copies have drifted" "run ./tools/build-tools.sh to resync"; fi + +# The JetBrains plugin is off by default: the first build downloads over a +# gigabyte of IntelliJ SDK, which does not belong in a test run. Once the Gradle +# cache is warm it takes seconds, so it is one env var away. +# LUDIC_TEST_JETBRAINS=1 ./tools/test-tools.sh +if [ "${LUDIC_TEST_JETBRAINS:-0}" = "1" ]; then + JB=tools/editors/jetbrains + if [ -x "$JB/gradlew" ]; then + ( cd "$JB" && ./gradlew buildPlugin verifyPluginStructure --console=plain -q ) >/dev/null 2>&1 \ + && [ -f "$JB/build/distributions/Ludic-1.0.0.zip" ] \ + && ok "jetbrains plugin builds and verifies" \ + || bad "jetbrains plugin build" "cd $JB && ./gradlew buildPlugin (needs JDK 17-21)" + # the lexer/highlighter/PSI tests run headless in a real platform fixture + ( cd "$JB" && ./gradlew test --console=plain -q ) >/dev/null 2>&1 \ + && ok "jetbrains platform tests (lexer, file type, PSI, folding)" \ + || bad "jetbrains platform tests" "cd $JB && ./gradlew test" + # the Plugin Verifier is what catches API breakage against a real IDE build. + # -q swallows its console output, so read the verdict it writes to disk. + ( cd "$JB" && ./gradlew verifyPlugin --console=plain -q ) >/dev/null 2>&1 + VERDICT=$(cat "$JB"/build/reports/pluginVerifier/*/plugins/*/*/verification-verdict.txt 2>/dev/null | head -1) + case "$VERDICT" in + Compatible) ok "plugin verified Compatible against the target IDE" ;; + Compatible*) bad "plugin verification: $VERDICT" "cd $JB && ./gradlew verifyPlugin" ;; + *) bad "plugin verification: ${VERDICT:-no verdict}" "cd $JB && ./gradlew verifyPlugin" ;; + esac + else + echo " skip jetbrains plugin (no gradle wrapper)" + fi +else + echo " skip jetbrains plugin build (set LUDIC_TEST_JETBRAINS=1)" +fi + +# The vocabulary lives in one place; drift between it and the copies that cannot +# include it (the TextMate grammar, the Kotlin lexer) is the failure mode this +# whole layout is meant to prevent, so it is checked rather than trusted. +python3 tools/check-vocabulary.py && ok "vocabulary in sync across grammar/lexer/header" || bad "vocabulary drifted" + +echo +echo "$PASS passed, $FAIL failed" +[ $FAIL -eq 0 ]