# OrbaLang User Guide

OrbaLang is a **transpilation-first business-logic language**. You write one
deterministic **function** or **rule** in a small, readable syntax; the toolchain
validates it and emits equivalent code, JSON, or documentation for multiple targets.

This guide is the primary training material for **v0.3-alpha**.

---

## 1. Quick start

### Install

Requirements: **Node.js 18+** and **npm**.

```bash
git clone https://github.com/luigipascal/Orbalang.git
cd Orbalang
npm install
```

### Your first transpile

**Function program** (calculation):

```bash
npm run orba -- examples/invoice.orba --target python
npm run orba -- examples/invoice.orba --target typescript --out build/invoice.ts
```

**Rule program** (governance validation):

```bash
npm run orba -- examples/high_value_payment.orba --target python-rule
npm run orba -- examples/invoice_approval.orba --target markdown
npm run orba -- examples/high_value_payment.orba --target json
```

On Windows PowerShell, the `--` after `orba` forwards flags through npm.

### Verify the toolchain

```bash
npm test          # unit + conformance tests
npm run launch    # full test suite + emit all examples to build/launch/
npm run ci        # same gate as GitHub Actions (test + emit)
```

Pull requests run **GitHub Actions** (`.github/workflows/ci.yml`): Jest on Ubuntu with
Python 3.12 for conformance, then launch emit for every example.

### CLI reference

```bash
# Function programs — transpile to a language
npm run orba -- <file.orba> --target python|typescript|sql|java|csharp|go|cobol|rpg|abap|sas [--out <file>]

# Rule programs — validation functions
npm run orba -- <file.orba> --target python-rule|typescript-rule|cobol-rule|rpg-rule|abap-rule|sas-rule [--out <file>]

# Both program types — documentation / canonical JSON
npm run orba -- <file.orba> --target json|markdown [--out <file>]

# Function programs only
npm run orba -- <file.orba> --schema [--out schema.json]   # JSON Schema for I/O
npm run orba -- <file.orba> --ir [--out module.json]       # OSIR debug dump

# Lint (functions and rules)
npm run orba -- <file.orba> --lint [--strict] [--out report.txt]
```

| Target | Applies to | Output |
| ------ | ---------- | ------ |
| `python`, `typescript`, `sql`, `java`, `csharp`, `go` | Function | Executable business logic |
| `python-rule`, `typescript-rule` | Rule | `{ passed, required_action, audit }` validator |
| `cobol-rule`, `rpg-rule`, `abap-rule`, `sas-rule` | Rule | Legacy validation procedure/macro |
| `json`, `markdown` | Function or rule | Semantic IR JSON or human-readable docs |

Requesting the wrong target for a program type produces a clear error (e.g.
`python-rule` on a function, or `python` on a rule).

Errors report **file:line:column** with a clear validation message.

---

## 2. Mental model

| Concept | Meaning |
| -------- | -------- |
| One file = one declaration | Either one **function** or one **rule** — no imports, no multi-declaration files |
| Pure steps (functions) | Assignments and conditionals only — no loops |
| Typed everywhere | Inputs, outputs, and expressions are type-checked |
| Transpile, don't interpret | OrbaLang does not run your logic; it generates target code |
| Side effects are explicit | Use `external:` hooks; the host platform implements them |
| Rules express governance | *When* a condition holds, *what* approval is required, *why* (audit metadata) |

OrbaLang is **not** a general-purpose language. It is for portable business rules:
pricing, approvals, caps, tax, eligibility, and similar calculations — plus
**governed policies** that auditors and operators can read and review.

### Three ways to express “rules”

OrbaLang has three related constructs. Do not confuse them:

| Construct | Where | Purpose | Transpiles as |
| --------- | ----- | ------- | ------------- |
| **Top-level rule program** | File starts with `rule Name` | Standalone governance policy with audit metadata | Validation function (`python-rule` / `typescript-rule`) or JSON/Markdown |
| **`govern` block** | Inside function `steps:` | Inline approval gate; raises at runtime when condition is true | Error/exception in target language |
| **`rule Name:` block** | Inside function `steps:` | Grouping for readability | Comments only — no semantic change |

---

## 3. Function program structure

Every function follows this order (only `input`, `output`, and `external` blocks
may be omitted):

```
function FunctionName          # PascalCase

audit:                         # optional — function-level metadata
  author: "team"
  version: "1.0"
  reason: "Why this rule exists"

input:                         # required for most programs
  name: Type

output:                        # at least one output (including return value)
  result: Type

external:                      # optional — platform hooks
  HookName(param: Type, ...)

steps:                         # required — business logic
  ...

return result                  # must name a declared variable
```

### Minimal example

```orba
function CalculateInvoiceTotal

input:
  amount: Decimal
  taxRate: Decimal

output:
  total: Decimal

steps:
  tax = amount * taxRate
  total = amount + tax

return total
```

See `examples/invoice.orba`.

---

## 4. Top-level rule programs (v0.3-alpha)

A **rule program** is a first-class file type for governed business logic. It
declares inputs, a Boolean condition, a required action, and optional audit metadata.

```
rule RuleName                  # PascalCase

input:                         # typed context for when:
  name: Type

when:                          # Boolean condition
  expression

then:                          # at least one action
  require approval from "RoleName"
  deny with reason "Why blocked"
  escalate to "EscalatorRole"

audit:                         # optional but recommended
  reason: "Why this policy exists"
  category: "Control area"
  severity: "High"
  owner: "Team"
  evidence: "Optional reference"
```

### Example

```orba
rule HighValuePaymentApproval

input:
  amount: Decimal
  currency: Text

when:
  amount > 10000

then:
  require approval from "TreasuryManager"

audit:
  reason: "High-value payment requires treasury approval"
  category: "Treasury Control"
  severity: "High"
  owner: "Treasury"
```

See `examples/high_value_payment.orba` and `examples/invoice_approval.orba`.

### Generated validation output

`python-rule` and `typescript-rule` emit a function that returns a structured result:

- **`passed: true`** — condition not met; no action required
- **`passed: false`** — condition met; `required_action` names the approval role and `audit` carries metadata

Wire this into your host application’s approval workflow (OrbaLang does not call
approvers directly).

### Rule validation (compiler enforces)

1. Rule must have a name.
2. Input names must be unique; types must be supported.
3. `when:` may only reference declared inputs.
4. `when:` must be **Boolean**.
5. `then:` must contain at least one action.
6. `require approval from "Role"` must have a non-empty role string.
7. `deny with reason "..."` must have a non-empty reason string.
8. `escalate to "Role"` must have a non-empty role string.
9. Audit fields are optional; if present they must be strings.
10. Invalid rules do not generate output.

---

## 5. Semantic IR

**Semantic IR** (`src/ir.ts`) is the canonical internal representation of an
OrbaLang program’s meaning. Both functions and rules lower to the same schema:

- `SemanticFunction` — inputs, outputs, steps, return name, audit
- `SemanticRule` — inputs, `when`, `then` actions, audit

The `--target json` CLI flag emits Semantic IR as JSON. `--target markdown`
produces human-readable documentation from the same structure.

Function programs also lower to **OSIR** (`src/osir.ts`) for the six-language
emit pipeline (`python`, `typescript`, `sql`, `java`, `csharp`, `go`). The path is
**AST → Semantic IR → OSIR** (`semanticFunctionToOsir`). Use `--ir` to dump OSIR
for debugging (functions only).

Semantic IR is the foundation for future targets (SQL, Java, C#, Go rule validators,
and legacy backends such as COBOL, RPG, ABAP, SAS).

---

## 6. Types

| OrbaLang | Meaning | Python | TypeScript | Java | C# | Go |
| -------- | ------- | ------ | ---------- | ---- | -- | -- |
| `Text` | string | `str` | `string` | `String` | `string` | `string` |
| `Integer` | whole number | `int` | `number` | `long` | `long` | `int64` |
| `Decimal` | money / ratio | `float` | `number` | `BigDecimal` | `decimal` | `float64` |
| `Boolean` | true/false | `bool` | `boolean` | `boolean` | `bool` | `bool` |
| `Date` | ISO date string | `str` | `string` | `String` | `string` | `string` |

`Date` values are **ISO-8601 strings** (e.g. `"2026-06-25"`) at runtime in
generated code. Use `dateDiff`, `isBefore`, and `isAfter` for date logic.

---

## 7. Expressions

### Literals

```
42          # Integer
3.14        # Decimal
"hello"     # Text
true        # Boolean
false
```

### Operators

```
+  -  *  /          # numeric (+ also concatenates Text + Text — both sides must be Text)
>  <  >=  <=  ==  !=   # comparison
and  or             # Boolean logic
```

Expressions also support parenthesized grouping — `(a + b) * c` — and unary
minus (`-5`, `-fee`). Dividing by a literal `0` is a validation error.

### Function calls (stdlib)

| Function | Args | Returns | Notes |
| -------- | ---- | ------- | ----- |
| `round(value, scale)` | Decimal, Integer | Decimal | HALF_UP rounding |
| `min(a, b)` | two numerics | Decimal | |
| `max(a, b)` | two numerics | Decimal | |
| `coalesce(primary, fallback)` | Text, Text | Text | empty primary → fallback |
| `length(text)` | Text | Integer | |
| `dateDiff(start, end)` | Date, Date | Integer | days from start to end |
| `isBefore(a, b)` | Date, Date | Boolean | |
| `isAfter(a, b)` | Date, Date | Boolean | |

Example: `examples/stdlib_round.orba`.

### Naming in generated code

| Item | OrbaLang | Python | TypeScript / Java / C# / Go |
| ---- | -------- | ------ | --------------------------- |
| Function | `CalculateTotal` | `calculate_total` | `calculateTotal` |
| Rule | `HighValuePaymentApproval` | `high_value_payment_approval` | `highValuePaymentApproval` |
| Variables | `taxRate` | `tax_rate` | `taxRate` |

---

## 8. Conditionals (`if` / `else` / `end`)

Indentation is **not** semantic. Blocks are closed with `end`:

```orba
steps:
  if amount >= 1000:
    discount = amount * 0.1
  else:
    discount = 0.0
  end
  total = amount - discount
```

Rules:

- The condition must be **Boolean**.
- A variable **first assigned inside** an `if` and used later must be assigned
  on **every branch** (use `else` or assign before the `if`).
- Nest `if` inside `else` for multi-way logic (no `else if` keyword).

Examples: `examples/discount.orba`, `examples/shipping.orba`.

---

## 9. Audit metadata

### Function audit

Attach provenance to a function (recommended for production logic):

```orba
audit:
  author: "treasury"
  version: "1.1"
  reason: "Monthly close calculation"
```

At least one of `author`, `version`, or `reason` is required inside `audit:`.
Transpilers emit these as comments in generated code.

### Rule audit

Top-level rules use a richer audit block (`reason`, `category`, `severity`,
`owner`, `evidence`). All fields are optional strings; AI lint warns if a
production rule has no `audit:` block.

---

## 10. External hooks

Declare platform-specific side effects without implementing them in OrbaLang:

```orba
external:
  SendEmail(to: Text, subject: Text, body: Text)

steps:
  _ = SendEmail(userEmail, "Notice", body)
```

Rules:

- Every called external must be declared in `external:`.
- Argument count and types are validated.
- Generated code includes **stub functions** that throw until your platform
  replaces them with real integrations.

Example: `examples/external_notify.orba`.

*(External hooks apply to function programs only.)*

---

## 11. Rule blocks (grouping inside functions)

`rule` blocks inside `steps:` group steps for readability and audit trails. They
transpile as comments in target languages — they do **not** change semantics:

```orba
steps:
  rule ApplyCap:
    capped = amount
  end
  total = capped
```

This is **not** the same as a top-level `rule RuleName` program (§4).

Example: `examples/rule_cap.orba`.

---

## 12. Governance policies (inside functions)

Governance blocks express **when human approval is required** inline inside a
function’s `steps:`:

```orba
steps:
  govern OverDailyLimit:
    when: amount > dailyLimit
    then: require approval "manager"
    audit:
      reason: "Payment exceeds daily limit"
  end
```

- `when:` must be a **Boolean** expression.
- `then: require approval "role"` names the approver role (string literal).
- Per-policy `audit:` is optional but recommended (AI lint warns if missing).

Generated code raises a runtime error when the condition is true — wire this
to your real approval workflow in the host application.

This differs from top-level rule programs (§4), which emit standalone validation
functions instead of raising inside a calculation.

Example: `examples/payment_governance.orba`.

---

## 13. Example catalogue

| File | Teaches |
| ---- | ------- |
| `invoice.orba` | Function basics — inputs, steps, return |
| `discount.orba` | Single `if` / `else` |
| `shipping.orba` | Nested conditionals |
| `payment_approval.orba` | Boolean logic |
| `payment_governance.orba` | Inline `govern` policies |
| `high_value_payment.orba` | Top-level rule — treasury approval |
| `invoice_approval.orba` | Top-level rule — finance approval |
| `blocked_payment.orba` | Top-level rule — deny action |
| `high_risk_escalation.orba` | Top-level rule — escalate action |
| `external_notify.orba` | External declarations |
| `rule_cap.orba` | Scoping rule blocks (inside `steps:`) |
| `stdlib_round.orba` | Stdlib (`round`, `min`, `max`, `dateDiff`) |
| `coalesce_display.orba` | `coalesce()` for Text |

Suggested learning path:

1. Functions — follow the table from `invoice.orba` through `payment_governance.orba`.
2. Rules — transpile `high_value_payment.orba` to `python-rule`, `typescript-rule`, `json`, and `markdown`.
3. Compare inline `govern` (inside a function) vs top-level rule (standalone validator).

**Hands-on track:** [Exercise Books](exercises/README.md) — six progressive workbooks with
starter files (`exercises/starters/`) and reference solutions (`exercises/solutions/`).

---

## 14. Validation rules (what the compiler enforces)

### Functions

1. Function must have a name.
2. Input and output names must be unique within their blocks.
3. Step variables must be unique (except when assigning to a declared output);
   `rule` blocks share the enclosing block's scope, so they cannot re-assign either.
4. `return` must reference a variable that exists **and is assigned on at least one path**.
5. Expressions may only use declared inputs, prior steps, or outputs.
6. Unsupported types and operators are rejected.
7. `if` / `when` conditions must be Boolean.
8. Definite assignment across branches (see §8).
9. Operand types must match the operator (numeric math, Boolean logic, etc.).
10. External calls must match declarations; step variables may not shadow external hooks.
11. Assignments must keep one type per variable: a value assigned to a declared
    output must match its declared type, and a variable may not be assigned
    conflicting types across branches.
12. Division by a literal `0` is rejected. `round(x, scale)` requires an Integer scale.

### Rules

See §4 (rule validation list). Invalid rules are rejected before any code generation.

---

## 15. What OrbaLang does not support

By design (to keep transpilation deterministic):

- Loops (`for`, `while`)
- `else if` as syntax (nest instead)
- Early `return`, `break`, `continue`
- Functions calling other OrbaLang functions
- Classes, inheritance, async/await, exceptions in source
- Direct database, file, or network I/O (use `external:`)
- Multiple `then:` actions: `require approval from`, `deny with reason`, `escalate to` — emitters use the first action as `required_action` and list the rest in `additional_actions`

Legacy **function** targets (`cobol`, `rpg`, `abap`, `sas`) emit code for
**subset-compliant** functions only — `validateLegacySubset` rejects externals,
governance, rule blocks, and unsupported stdlib calls per target. **Rule**
programs use `cobol-rule`, `rpg-rule`, `abap-rule`, and `sas-rule`.

---

## 16. Targets and SQL note

| Target | CLI `--target` | Program | Notes |
| ------ | -------------- | ------- | ----- |
| Python | `python` | Function | Default learning target |
| TypeScript | `typescript` | Function | Strict-friendly hoisting |
| SQL | `sql` | Function | Single `SELECT` expression; governance as comments |
| Java | `java` | Function | `BigDecimal` for decimals |
| C# | `csharp` | Function | `decimal` literals |
| Go | `go` | Function | `float64` for decimals |
| COBOL | `cobol` | Function | Legacy subset — PROCEDURE DIVISION |
| RPG | `rpg` | Function | RPG IV free-form procedure |
| ABAP | `abap` | Function | ABAP method |
| SAS | `sas` | Function | SAS macro |
| Python rule | `python-rule` | Rule | Returns `{ passed, required_action, audit }` |
| TypeScript rule | `typescript-rule` | Rule | Same structure as Python rule |
| COBOL rule | `cobol-rule` | Rule | COBOL validation program |
| RPG rule | `rpg-rule` | Rule | RPG IV free-form procedure |
| ABAP rule | `abap-rule` | Rule | ABAP method with exporting flags |
| SAS rule | `sas-rule` | Rule | SAS macro with pass/fail variables |
| JSON | `json` | Both | Semantic IR |
| Markdown | `markdown` | Both | Human-readable docs |

Conformance tests (Python vs TypeScript numeric agreement) run on function
programs: `invoice.orba`, `discount.orba`, and `payment_approval.orba`.

Rule programs `high_value_payment.orba` and `invoice_approval.orba` are checked
for agreement between `python-rule` and `typescript-rule` outputs.

---

## 17. Troubleshooting

| Problem | Fix |
| ------- | --- |
| `Expected 'steps:' block` | Block order: `audit` → `input` → `output` → `external` → `steps` |
| `Condition of 'if' must be Boolean` | Use comparisons or `and`/`or`, not arithmetic |
| `Reference to undeclared name` | Assign the variable before use, or add to `input:` |
| `Variable used after conditional` | Add `else` branch that assigns the same variable |
| `Target 'python' requires a function program` | Use `--target python-rule` for rule files |
| `Target 'python-rule' requires a rule program` | Use `--target python` for function files |
| npm swallows flags | Use `npm run orba -- file.orba --target python` |

---

## 18. Further reading

- [README.md](../README.md) — install, roadmap, Jira programme
- [tests/](../tests/) — exhaustive behaviour examples (`semantic_rules.test.ts` for rules)
- Jira epic [LANG-1](https://senariogen.atlassian.net/browse/LANG-1)

For questions or gaps in this guide, open a **LANG** ticket in Jira.
