Download the Jarlang Executable Runner:
Jarlang Executable Runner (Google Drive)
- Download or build
jarlang.jar(found in theJarlangRunnerdirectory). - Start the Jarlang shell (REPL):
java -jar JarlangRunner/jarlang.jar
- Inside the shell, run a
.vasefile with:!run yourfile.vase
- Add executable permissions to run_jarlang.py (remember to always look deeply at scripts before giving permissions or running)
-TODO: MODE TO BE ADDED HERE WHEN DOCKER is working
- Declare with
wield:wield x 10 wield name "JarKnight"
- Numbers can be integers or floats:
wield a 42 # int wield b 3.14 # double wield s "hello" # string
- Use
judgeandorjudgefor if/elif/else:wield n 5 judge n > 0 mend chant "positive" orjudge n == 0 mend chant "zero" orjudge mend chant "negative"
- Define with
forge, return withmend:forge add(a, b) mend a + b chant add(2, 3) # prints 5
- While loop:
lestwield i 0 lest i < 3 { chant i i = i + 1 } - For loop:
endureendure wield j 0; j < 3; j = j + 1 { chant j }
- Concatenate with
+:wield greeting "Hello, " + name chant greeting
- Import helpers:
summon "stdlib.vase" chant commune(3, 4) # prints 7.0
Jarlang is a small, warrior-themed expression language and learning interpreter implemented in Java. It’s designed for clarity and experimentation — the syntax uses themed keywords (forge/wield/chant/summon/judge/lest/mend) while providing familiar arithmetic, control flow, functions, and a small standard library.
This README documents the language syntax, runtime semantics, developer extension points, and the current standard library provided in stdlib.vase.
- Start the REPL (if provided by your runner), or call
!run filename.vaseinside the REPL. - Standard library functions are located in
stdlib.vaseand are imported withsummon "stdlib.vase".
- Comments: single-line comments start with
#and run to the end of line. - Identifiers: letters, digits and
_, must start with a letter. - Strings: double-quoted characters, e.g.
"Hello". - Numbers: integers (
42) and floats (3.14). - Tokens include operators and punctuation:
- Arithmetic:
+(commune),-(banish),*(rally),/(slash),^(ascend) - Comparison:
==,!=,<,>,<=,>= - Assignment:
=(bind) - Grouping:
()and{} - Delimiters:
,:;
- Arithmetic:
wield— declare a variable (e.g.,wield x 10)forge— begin a function definition (e.g.,forge add(a, b) ...)mend— return from a function or end a single-linejudgebranchchant— print / output expression (likeprint)summon— import another.vasefile into the current contextjudge— if / conditional branchorjudge— else-if / chained conditional branchlest— while loop (likewhile)gather/disperse— parentheses (internal naming; symbol tokens are(and))
Note: Keywords are mapped to token types internally; your code uses the literal words above.
- Arithmetic expressions obey standard precedence:
- Parentheses
( ... ) - Exponentiation
^ - Multiplication/Division
*/ - Addition/Subtraction
+-
- Parentheses
- Unary operators:
-xand+xand logical!x(if implemented). - Example:
chant (3 + 4) * 2 # prints 14
+in expressions will perform numeric addition for numbers, and string concatenation if either operand is a string (the interpreter coerces or prefers string concatenation for string operands).
- Variable declaration:
wield <name> <expression>- Example:
wield x 10
- Assignment:
<name> = <expression>- Example:
x = x + 1
- Print:
chant <expression>- Example:
chant "Hello",chant x + 1
- Blocks:
- Use
{ ... }for grouped statements (parser supports block nodes).
- Use
- Semicolons are optional separators at top-level; the parser is flexible about separators between statements.
- If / elif / else (themed):
judge <condition> mend <expr-or-block> [orjudge <condition> mend <expr-or-block>]...- Example:
judge x > 0 mend
chant "positive"
orjudge x == 0 mend
chant "zero"
orjudge mend
chant "negative"
- While loop:
lest <condition> { <statements> }- Example:
wield i 0
lest i < 5 {
chant i
i = i + 1
}
- Define:
forge add(a, b)
mend a + b
- Return:
- Use
mend <expression>inside a function to return immediately with a value. - If no explicit
mendis used in a function-body block, the last evaluated expression is treated as the result.
- Use
- Call:
chant add(2, 3)
- Functions capture the current context as closure when defined (see
JarlangFunction).
summon "<filename>.vase"executes another file and injects its top-level definitions into the current context.- The runner provides
runFileIntoContextto avoid re-importing the same file multiple times.
- The runtime currently operates with these value kinds:
- Numbers (Double)
- Strings
- Objects (for builtin types like
JarlangArray, orJarlangFunction)
- The interpreter uses a
Resultclass to represent evaluation results (NUMBER / STRING / OBJECT). Builtins and context storage prefer raw Java types (Double, String, JarlangArray) for compatibility.
The project ships with stdlib.vase. Key helpers include:
-
Numeric utilities:
commune(a,b),banish(a,b),rally(a,b),slash(a,b),ascend(a,b)— arithmetic wrappersmax(a,b),min(a,b),clamp(x,lo,hi)abs(x),sign(x),sqrt(x),pow_int(a,n),fact(n),fib(n)gcd(a,b),lcm(a,b),map_range(...),hypot(a,b),deg2rad,rad2degis_even,is_odd,is_prime
-
Utilities:
add1(x)— conveniencesumTo(n),mean2(a,b),approx_equal(a,b,eps)
-
Small collection of string helpers have been added to
stdlib.vase(pure-vase):concat(a,b)— concatenation wrappertale_repeat(s,n)— repeat stringsntimesbarren_tale(s)— string emptiness test
(See stdlib.vase for the full list and implementations.)
- Builtins are Java functions stored in the
Context— seelib/JarlangCollections.javafor an exampleBuiltinFunctioninterface and array helpers. - To add a builtin:
- Implement a
BuiltinFunctionobject (a lambda or an implementation of the interface). - Register it in the global context with
ctx.setVariable("<name>", builtinFunction). - The
FunctionCallNoderecognizes and invokesBuiltinFunctioninstances.
- Implement a
- Builtins should accept raw Java values (Double, String, objects) and return raw Java values. The interpreter converts between
Resultand raw objects at call boundaries.
- Error types:
IllegalCharError— lexical errors (bad characters, unterminated string)SyntaxError— parser errors (unexpected token, missing), etc.)InterpreterError— runtime errors (division by zero, undefined variable, type mismatch)
- Position tracking:
- The lexer attaches
Positionobjects to tokens (idx, line, column). - Errors include position and — when available — filename for helpful messages.
- The lexer attaches
- Example error message:
SyntaxError: Expected ')' in main.vase at line 3, column 14 (idx: 14)
- You can run single-file tests with the included runner:
./run.sh tests/my_test.vase
- Tests are regular
.vasescripts thatchantoutputs for manual verification. - Example test pattern:
summon "stdlib.vase"
chant "== TEST =="
chant commune(7,7)
- Recommended practice: keep small focused tests under
tests/that exercise individual stdlib functions and control flow.
- Use
chantliberally to inspect values while developing. - Add temporary debugging prints inside Java code (e.g., in
VariableNode.evaluate) to inspect context contents. - Common issues:
- Mixing
Resultobjects with raw Java values when storing to Context — ensure arguments are unwrapped before storing. - Forgetting to register builtins in the global context.
- Indexing, bounds, and type mismatches from partial refactors.
- Mixing
-
Test Suite Library:
- Added
testlib.vase, a pure-vase test helper library with assertion functions (assert_eq,assert_true, etc.), pass/fail counters, and summary reporting. This makes it easy to write automated tests for language features and standard library functions.
- Added
-
Vow/Sacred Types:
- The language now supports
vowandsacredvariable declarations, enforcing immutability and special semantics for constants and protected variables. Reassignment to these types is prevented at runtime.
- The language now supports
-
Endure Loops:
- Added the
endurekeyword for for-loop style iteration, supporting initializer, condition, increment, and loop body. This complements the existinglest(while) loop and enables more expressive control flow.
- Added the
-
Code lives under
lib/:jarlang.java— lexer, parser, AST nodes, interpreter core.JarlangCollections.java— example builtins and helper types (arrays).JarlangFileRunner.java,JarlangShell.java— runner/REPL utilities.
-
Adding syntax (array literal, indexing) requires coordinated changes to:
- Lexer (new tokens), Parser (factor/primary handling), AST (ArrayNode, AccessNode), and Interpreter (Result/Object handling).
- Prefer small incremental changes and frequent compile/test cycles.
- Use the project’s naming flavor — warrior/medieval words — for user-facing keywords and builtins (e.g.,
summon,forge,chant,cohort_*). - Keep
Contextstorage as plain Java values (Double/String/Object); avoid storingResultexcept transiently. - Write small unit tests in
tests/for each change. Aim for a tight edit–compile–test loop.
Function definition and call:
forge greet(name)
mend "Hello, " + name
chant greet("Adam") # Hello, Adam
Conditional and loops:
wield n 5
judge n <= 1 mend
chant "trivial"
orjudge mend
wield i 0
lest i < n {
chant i
i = i + 1
}
Import and use stdlib:
summon "stdlib.vase"
chant commune(3, 4) # 7.0
The JarKnight mascot was created to represent the spirit of Jarlang: playful, bold, and ready for battle! Below is the visual journey from sketch to final mascot, showing each stage of the design process:
Each image above shows a step in the mascot's evolution, from initial concept to the polished JarKnight you see at the top of this README!
Download the Jarlang Executable Runner:
Jarlang Executable Runner (Google Drive)
Copyright © Adam Lenarduzzi 2025 — Jarlang







