Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# AI panel backend config. Copy to `.env` and fill in if overriding defaults.
# Both vars are optional — they default to the shared dev server on torta-server.

# k12-llm-backend URL (defaults to https://k12api.torta-server.duckdns.org)
VITE_BACKEND_URL=

# Keycloak URL (defaults to https://auth.torta-server.duckdns.org)
VITE_KEYCLOAK_URL=
VITE_KEYCLOAK_REALM=
VITE_KEYCLOAK_CLIENT_ID=
2 changes: 1 addition & 1 deletion csv/praxly.test.csv
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Print twice,"print ""1st""
print ""2nd""",,"1st
2nd",
Declare integer,"int x
print x",,0,
print x",,,Runtime Error: Uninitialized variable 'x'
Assign integer,"int x <- 5
print x",,5,
Declare assign,"int x
Expand Down
2 changes: 1 addition & 1 deletion docs/AST_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Every AST node type defined in [`src/language/ast.ts`](../src/language/ast.ts),
- **Statement / declaration nodes** are dispatched by `ASTVisitor.visitStatement()` to an abstract `visitX()` method that every emitter (`java`, `python`, `csp`, `praxis`, `javascript`) must implement.
- **Expression nodes** have no `visitX()` counterpart — they're handled inside each emitter's own `generateExpression(expr, parentPrecedence)` switch statement instead.
- **Nested/helper nodes** (`Parameter`, `SwitchCase`, `ExceptionHandler`) aren't dispatched on their own, and aren't part of the `Statement` union either — they're plain data read directly by the parent node's visit method (e.g. `visitSwitch` iterates `stmt.cases`).
- **Comments** travel with the AST rather than being discarded: any node may carry `leadingComments` (own-line comment lines directly above it) and `trailingComment` (an inline comment on the same line), and `Program` carries `headerComments` (the file-top block). Lexers capture single-line comments, a shared pass attaches them by source position, and each emitter re-emits them in the target's comment delimiter (`//` or Python `#`), so comments survive translation.
- **Comments** travel with the AST rather than being discarded: any node may carry `leadingComments` (own-line comment lines directly above it, including a file-top comment block, which attaches to the first statement) and `trailingComment` (an inline comment on the same line). Lexers capture single-line comments, a shared pass attaches them by source position, and each emitter re-emits them in the target's comment delimiter (`//` or Python `#`), so comments survive translation.

| Node Type | Visitor Method | Explanation |
| --------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down
78 changes: 78 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,81 @@ npm run test:run -- tests/examples.test.ts

`tests/examples.test.ts` parses, interprets, and translates every demo as a
regression guard, so the files stay runnable as the codebase evolves.

## Language-Specific Notes

### CSP

CSP is a small procedural language, so it reaches fewer AST nodes than the
other demos.

AST nodes NOT reachable from CSP source (covered by the other demos):
- Classes (ClassDeclaration/Constructor/Method/Field), NewExpression,
- MemberExpression, ThisExpression .... CSP has no usable OOP.
- DoWhile / RepeatUntil node .......... `REPEAT UNTIL` maps to While(NOT c).
- Switch / Try / Break / Continue ..... no such keywords.
- ConditionalExpression (ternary) ..... not parsed.
- UpdateExpression (++/--) ............ not in CSP.
- CompoundAssignment (+=) ............. write `x ← x + 1`.

Interpreter notes:
- Assignment is `←` (ASCII `<-` also accepted); `=` means EQUALITY.
- Lists are 1-based (AP CSP).
- `REPEAT UNTIL(c)` is a PRE-condition loop (runs while NOT c).
- There is no counting FOR: use a counter + REPEAT UNTIL, or REPEAT n TIMES.
- There is no unary minus -> write `0 - x`. There is no `null`.
- DISPLAY prints its argument followed by a SPACE (no newline), per AP CSP,
so all output below lands on a single space-separated line.

### Java

AST nodes NOT reachable from Java source (covered by the other demos):
- FunctionDeclaration ..... Java has only methods, never free functions.
- RepeatUntil ............. no repeat/until syntax.
- NewExpression ........... `new X(...)` is encoded as a CallExpression.
- ThisExpression .......... `this` is encoded as an Identifier.

Interpreter notes:
- System.out.println takes exactly ONE argument -> concatenate with '+'.
- A C-style for-loop update should be `i++` (an embedded plain assignment
like `i = i + 1` is a no-op).
- Scanner reads System.in, which the auto-runner can't supply, so Scanner is
exercised by the Java tests (with provided input) rather than here.

The executable code lives in Main.main (auto-invoked by the interpreter);
the helper classes it uses are declared afterwards.

### JavaScript

AST nodes NOT reachable from JavaScript source (covered by the other demos):
- RepeatUntil ......... no repeat/until syntax.

Interpreter notes:
- Output is console.log(...) (multiple args are space-joined).
- Standard JS: arrays use .push, conversions use parseInt/parseFloat/String,
integer division uses Math.trunc, .length gives length.
- `let`/`const`/`var` all behave identically (no block scoping enforced).

### Praxis

Praxis maps most directly to the Universal AST, so it reaches the widest
set of nodes.

AST nodes NOT reachable from Praxis source (covered by the other demos):
- Switch / SwitchCase .. no switch/case keywords.
- ConditionalExpression no ?: ternary operator.
- CompoundAssignment ... no +=/-=; write `x ← x + 1`.
- ForEach .............. no for-each; Praxis has only the C-style for loop.

Functions and classes are hoisted, so the driver calls them before their
declarations appear further down the file.

### Python

AST nodes NOT reachable from Python source (covered by the other demos):
- DoWhile / RepeatUntil ... no do-while / repeat syntax.
- Switch / SwitchCase ..... no match/switch parsing.
- UpdateExpression ........ no ++ / -- in Python.
- CompoundAssignment ...... += etc. desugar to Assignment + BinaryExpression.
- NewExpression ........... instantiation is a CallExpression, e.g. Dog("x").
- ThisExpression .......... `self` is an ordinary Identifier.
102 changes: 38 additions & 64 deletions examples/demo.csp
Original file line number Diff line number Diff line change
@@ -1,51 +1,25 @@
// ===========================================================================
// Praxly2 feature demo -- CSP (shared notes: examples/README.md)
// ---------------------------------------------------------------------------
// CSP is a small procedural language, so it reaches fewer AST nodes than the
// other demos.
//
// AST nodes NOT reachable from CSP source (covered by the other demos):
// Classes (ClassDeclaration/Constructor/Method/Field), NewExpression,
// MemberExpression, ThisExpression .... CSP has no usable OOP.
// DoWhile / RepeatUntil node .......... `REPEAT UNTIL` maps to While(NOT c).
// Switch / Try / Break / Continue ..... no such keywords.
// ConditionalExpression (ternary) ..... not parsed.
// UpdateExpression (++/--) ............ not in CSP.
// CompoundAssignment (+=) ............. write `x <- x + 1`.
//
// CSP runtime facts honored below:
// * Assignment is `<-` (or the unicode arrow); `=` means EQUALITY.
// * Lists are 1-based (AP CSP).
// * `REPEAT UNTIL(c)` is a PRE-condition loop (runs while NOT c).
// * There is no counting FOR: use a counter + REPEAT UNTIL, or REPEAT n TIMES.
// * There is no unary minus -> write `0 - x`. There is no `null`.
// * DISPLAY prints its argument followed by a SPACE (no newline), per AP CSP,
// so all output below lands on a single space-separated line.
// ===========================================================================


// ========================== EXPRESSIONS ====================================

// ---- Literal (number, string, boolean) + Assignment + DISPLAY -------------
name <- "csp"
greeting <- "hello " + name // BinaryExpression '+' (string concatenation)
// ========================== EXPRESSIONS ======================================

// ---- Literal (number, string, boolean) + Assignment + DISPLAY ---------------
name ← "csp"
greeting ← "hello " + name // BinaryExpression '+' (string concatenation)
DISPLAY(greeting) // hello csp

flag <- true
flag true
DISPLAY(flag) // true

// ---- BinaryExpression: arithmetic + MOD (division is floating point) -------
total <- 3 + 4 * 2
// ---- BinaryExpression: arithmetic + MOD (division is floating point) --------
total 3 + 4 * 2
DISPLAY(total) // 11
DISPLAY(17 MOD 5) // 2
DISPLAY(10 / 4) // 2.5

// ---- No unary minus in CSP -> subtract from zero ---------------------------
neg <- 0 - 7
// ---- No unary minus in CSP -> subtract from zero ----------------------------
neg 0 - 7
DISPLAY(neg) // -7

// ---- Comparison + logical (AND / OR / NOT) incl. unicode relational forms --
x <- 5
// ---- Comparison + logical (AND / OR / NOT) incl. unicode relational forms ---
x 5
DISPLAY(x >= 5 AND x < 10) // true
DISPLAY(x = 5 OR x = 6) // true
DISPLAY(NOT (x = 3)) // true (UnaryExpression NOT)
Expand All @@ -54,76 +28,76 @@ DISPLAY(x ≠ 3) // true (unicode not-equal)
DISPLAY(x ≤ 5) // true (unicode less-or-equal)
DISPLAY(x ≥ 5) // true (unicode greater-or-equal)

// ---- ArrayLiteral + IndexExpression (1-based) + index Assignment -----------
nums <- [10, 20, 30]
// ---- ArrayLiteral + IndexExpression (1-based) + index Assignment ------------
nums [10, 20, 30]
DISPLAY(nums[1]) // 10 (first element is index 1)
nums[2] <- 99
nums[2] 99
DISPLAY(nums[2]) // 99

// ---- List builtins: APPEND / INSERT / REMOVE / LENGTH (1-based positions) --
// ---- List builtins: APPEND / INSERT / REMOVE / LENGTH (1-based positions) ---
APPEND(nums, 40) // [10, 99, 30, 40]
INSERT(nums, 1, 5) // [5, 10, 99, 30, 40] (insert before position 1)
REMOVE(nums, 2) // [5, 99, 30, 40] (remove position 2, the 10)
DISPLAY(LENGTH(nums)) // 4
DISPLAY(nums[1]) // 5

// ---- String functions: CONCAT / SUBSTRING / CHARAT / len (1-based) ---------
word <- "algorithm"
// ---- String functions: CONCAT / SUBSTRING / CHARAT / len (1-based) ----------
word "algorithm"
DISPLAY(CONCAT("al", "go")) // algo
DISPLAY(SUBSTRING(word, 1, 4)) // algo (characters 1..4, inclusive)
DISPLAY(CHARAT(word, 1)) // a (the first character)
DISPLAY(len(word)) // 9


// ========================== STATEMENTS =====================================
// ========================== STATEMENTS =======================================

// ---- IF / ELSE IF / ELSE ---------------------------------------------------
score <- 82
// ---- IF / ELSE IF / ELSE ----------------------------------------------------
score 82
IF (score >= 90)
{
DISPLAY("A")
}
ELSE IF (score >= 80)
{
DISPLAY("B") // this runs
DISPLAY("B") // this runs
}
ELSE
{
DISPLAY("C")
}

// ---- REPEAT UNTIL(c) -> pre-condition While(NOT c) -------------------------
i <- 0
// ---- REPEAT UNTIL(c) -> pre-condition While(NOT c) --------------------------
i 0
REPEAT UNTIL (i >= 3)
{
DISPLAY(i) // 0 1 2
i <- i + 1
i i + 1
}

// ---- REPEAT n TIMES -> count-based For -------------------------------------
// ---- REPEAT n TIMES -> count-based For --------------------------------------
REPEAT 3 TIMES
{
DISPLAY("tick") // tick tick tick
}

// ---- Counting loop: counter + REPEAT UNTIL (CSP has no FOR FROM/TO) --------
j <- 0
// ---- Counting loop: counter + REPEAT UNTIL (CSP has no FOR FROM/TO) ---------
j 0
REPEAT UNTIL (j >= 6)
{
DISPLAY(j) // 0 2 4
j <- j + 2
j j + 2
}

// ---- FOR EACH item IN list -------------------------------------------------
// ---- FOR EACH item IN list --------------------------------------------------
FOR EACH item IN nums
{
DISPLAY(item) // 5 99 30 40
DISPLAY(item) // 5 99 30 40
}


// ========================== FUNCTIONS ======================================
// ========================== FUNCTIONS ========================================

// ---- FunctionDeclaration (PROCEDURE) + Parameter + RETURN ------------------
// ---- FunctionDeclaration (PROCEDURE) + Parameter + RETURN -------------------
PROCEDURE add(x, y)
{
RETURN x + y
Expand All @@ -136,17 +110,17 @@ PROCEDURE isEven(n)

PROCEDURE printEvens(limit)
{
i <- 0
i 0
REPEAT UNTIL (i >= limit) // 0 .. limit-1
{
IF (isEven(i))
{
DISPLAY(i)
}
i <- i + 1
i i + 1
}
}

// ---- Procedure calls (CallExpression / ExpressionStatement) ----------------
DISPLAY(add(4, 5)) // 9
printEvens(6) // 0 2 4
// ---- Procedure calls (CallExpression / ExpressionStatement) -----------------
DISPLAY(add(4, 5)) // 9
printEvens(6) // 0 2 4
Loading
Loading