ox

The Ox programming language, compiler and tools (WIP)
Log | Files | Refs | README | LICENSE

NOTES.md (3795B)




[https://github.com/gingerBill/titania]
[https://news.ycombinator.com/item?id=45243925]
[https://people.inf.ethz.ch/wirth/Oberon/Oberon07.Report.pdf]
[https://people.inf.ethz.ch/wirth/ProjectOberon/PO.System.pdf]

add_operator = "+" | "-" | "xor" | "or".
mul_operator = "*" | "/" | "%"   | "and".

see
    Tokenizer Semicolon Insertion Rules

    When a newline is seen after the following token kind, a semicolon is inserted, otherwise no semicolon is inserted:

    ...list


Gleam my new obsession
I love Rust, but...
[https://ericcodes.io/blog/gleam-my-new-obsession.html]

(`antirez/sds` for dynamic strings, `nothings/stb_ds` for dynamic arrays and hashmaps, and `cxong/tinydir` for reading the filesystem).
[https://old.reddit.com/r/Compilers/comments/1nmc3r9/i_wrote_a_compiler_for_a_large_subset_of_c_in_c/]

How to make stuff private and discussion on design (just mangle the names if needed)
[http://journal.stuffwithstuff.com/2025/05/26/access-control-syntax]


# symbols

- jack      int             1
- test      void->void      1
    alice   float           2
- main      void->void      1
    peter   strings         2
- jill      int             1

# Zed

[https://zed.dev/docs/extensions/developing-extensions]

# libgccjit doco

[https://gcc.gnu.org/onlinedocs/gcc-15.1.0/jit/]

# license

  the hare license at the bottom
  https://sr.ht/~sircmpwn/hare/
  the standard library is under MPL, the compiler and executables are under GPL3

# walk down, compute bubbling up

RDP (Root‑Descend‑Process)

- Push "stacks" as you descend, nodes and local state
- Process and pop the frame off on the way back up and merge or "combine" result with its parent.

Expr ::= Add(Expr, Expr)
       | Mul(Expr, Expr)
       | Num(Int)

R‑D‑P Application

1. Root: Add( Mul(Num(2), Num(3)), Num(4) )
2. Descend:
  - Push Add frame.
  - Push left child Mul.
  - Push left child Num(2) → leaf → Process → result = 2.
  - Push right child Num(3) → leaf → Process → result = 3.
  - Process Mul → result = 6.
  - Push right child Num(4) → leaf → Process → result = 4.
3. Process Add → result = 10.

** Forget the whole tree, focus on this node and reason locally. **

R‑D‑P (Root‑Descend‑Process) turns recursive AST evaluation into a clear, iterative algorithm.
Pair it with bottom‑up traversal, the visitor pattern, or an explicit stack to keep state explicit.
This approach reduces cognitive load by isolating each node’s processing and avoiding hidden call‑stack dependencies.

Keep a whiteboard model of the tree shapes.

- Base case – literals and identifiers return a value immediately.
- Recursive step – always evaluate child nodes before applying the operator at the current node.
- After return – combine child results according to the operation; this is where side‑effects (e.g., assignment) may occur.

see [[TODO]]

## Only pure constant expressions are evaluated at compile time

print has side effects so it doesn't

2 + 3 is not run by the compiler, but it may be constant-folded in the optimizer.

you lower print to a runtime call printf

### CTFE compile time function execution

- constant expression, constant folding and propagation
- evaluator / constant interpreter
- restricted evaluator in the compiler, with env and CT heap
- try_ctfe on expression nodes
- lowering: emit literal value to IR once folded
- C++: consteval, Zig: comptime, Rust: constfn
- gate with fuel(?), depth restriction and memory limits


add_to_scope is used during semc
add_symbol is used during genc, feels wrong


when we semc we need to build the scope and symbols list for each
but then in gen we need to fetch the symbols and pad them with pointers

separate the gccjit impl to a separate tree than the symbols table of semantic analysis