Build Beyond Boundaries.
Scarp is an experimental programming language implemented in Rust. This checkout implements the 0.0.5-alpha.1 source-modules prerelease, extending the 0.0.4-alpha.4 numerical/runtime milestone. It has finite binary64 values, a lexer, parser, name resolver, interpreter and command-line interface. Syntax and library APIs may change.
Use immutable bind and mutable var declarations, checked integers, finite floats, strings,
booleans, conditionals, while/repeat loops, and explicit output streams.
Typed funcra functions support named/default arguments,
recursion, unit returns, purity, contracts, and bounded heap call frames.
See the migration guide for older declaration syntax.
// My first Scarp program
print("Hello from Scarp!");
Hello from Scarp!
The documentation hub provides setup, tutorials, command and diagnostic references, Rust embedding, testing, troubleshooting, and compatibility guides. Start there for a reading path matched to your task.
Source modules organize programs with relative .srp imports,
explicit aliases and public functions/scalar constants. Follow the
import tutorial, then run the three-file example:
cargo run --locked --offline -- run examples/module_demo.srp
cargo run --locked --offline -- check examples/module_demo.srpThe tile and linear-algebra guide covers immutable two-axis values, transpose, matrix-vector/matrix products and tile arithmetic. Shared vector windows keep their visible-slice boundaries through all operations.
bind weights = tile([1.0, 2.0, -1.0, 3.0], 2, 2);
print(matvec(weights, [2.0, 1.0])); // [4.0, 1.0]
Automatic value retirement releases inaccessible scope values while preserving returned values, contracts and output snapshots. Independent runtime budgets bound work, calls, slots, snapshots and cumulative new numerical payload. These do not measure total process memory.
Existing numerical capabilities include compensated vector reductions, scaled norms, softmax, log-space operations, deterministic selection, categorical losses, one-hot targets and explicit loss gradients. See vectors, the numerical tutorial, and error repairs.
The latest published prerelease is
0.0.5-alpha.1,
published from afe8b5380c9d6c4774162e51c6c9bc8b90901671 with verified Windows
x64, Linux x64 and macOS ARM64 packages. Read the
publication and verification record
for source, CI, checksums and public-download evidence. The
release preparation notes preserve the approved
source snapshot; see release engineering for future releases.
The maintainer transferred this repository to scarp-lang/scarp. The migration record documents identity, history, release/download verification and updated clone instructions.
Binary archives and checksums are available through GitHub Releases. See the 0.0.5-alpha.1 verification record for platform support, verification, and running an extracted package. The changelog records this version.
To build from source:
Install a stable Rust toolchain with Cargo using the instructions at rustup.rs. On Windows, use the MSVC toolchain and install the C++ build tools if the Rust installer requests them.
git clone https://github.com/scarp-lang/scarp.git
cd scarp
git switch main
cargo build --locked
cargo run -- run examples/hello.srp
cargo run -- run examples/arithmetic.srp
cargo run -- tokens examples/hello.srp
cargo run -- check examples/scopes.srp
cargo run -- --help
cargo run -- --versionThe project has no third-party Rust dependencies. After installing Rust, the
prototype can be built and tested offline with cargo build --offline and
cargo test --offline.
To install the command from this checkout:
cargo install --path . --locked
scarp run examples/hello.srp
scarp tokens examples/hello.srpFilenames with spaces should be quoted. Use scarp run -- -example.srp for a
filename beginning with a dash. Source paths use the platform's native path
encoding; source contents must be UTF-8. The .srp suffix is conventional, and
the CLI does not reject other filename extensions.
print("text");statements, executed in source order.- Multiple statements, empty strings, and empty or comment-only files.
- Signed 64-bit integers with
+,-,*,/, unary minus, and parentheses. - Operator precedence, left-associative binary operators, and checked arithmetic.
- Immutable integer/string/boolean bindings with
bind name = expression;and resolved names. - Explicit
varbindings, assignment, and checked compound assignment. - Lexical block scopes, shadowing, and nearest-binding assignment.
- Inferred primitive types, checked same-type assignment, and string value snapshots.
- Boolean comparisons and short-circuit
and,or, andnotexpressions. - Scoped
if/elif/elsestatements with explicit boolean conditions. whileand countedrepeatloops, nearest-loopbreak/continue.- Typed file-level
funcra, positional/named/default arguments, forward and mutual recursion, explicit returns, verified purity, and executable contracts. - Relative source modules, public/private functions and scalar literal constants, explicit filesystem/in-memory loaders, cycle diagnostics and bounded graphs.
- Heap call frames and seven deterministic CLI/embedding resource limits shared
by
runandcheck; see budgets. - Unicode text in strings and comments, Unicode whitespace, and LF or CRLF files.
- Optional UTF-8 byte order mark at the very start of a file.
//comments to the end of the line, and flexible whitespace between tokens.- Escapes
\\(backslash),\"(double quote),\n(LF),\t(tab), and\r(CR). run,check,tokens,--help/-h, and--version/-Vcommands.- Syntax errors with a code, filename, line, column, source excerpt, and help.
print appends a newline; write omits it. println remains a supported alias.
Both accept zero or more comma-separated values. eprint and ewrite use stderr.
See the output guide for exact bytes and embedding APIs. Physical line breaks inside a string are rejected;
use \n instead. Identifiers use ASCII letters, digits, and underscores, cannot
start with a digit, and are case-sensitive. Statements include declarations,
assignments, blocks, if/elif/else decisions, and print calls. Escapes other than the five listed
above are rejected.
The entire file is lexed, parsed, resolved, checked for primitive type consistency, and its selected execution path is evaluated before any program output is written. Source and semantic errors therefore produce no program output. Output stream failures propagate as errors; an output failure can occur after earlier statements have been written. A closed output pipe is treated as normal CLI termination.
print(1 + 2 * 3); // 7
print((1 + 2) * 3); // 9
print(-7 / 2); // -3, division truncates toward zero
print(-9223372036854775808); // the minimum signed 64-bit integer
Integer overflow, division by zero, and out-of-range literals are errors in both debug and release builds. Grouping is limited to 64 nested parentheses; long binary chains use a flat syntax tree. Strings can be bound, copied, reassigned with the same type, and printed. Concatenation and mixed string/integer arithmetic are unsupported.
Booleans use true and false. Comparisons support same-type == and !=,
and same-type numeric <, <=, >, >=. Readable not, and, and or operators require
booleans; and and or short-circuit at runtime while all operands are checked
for names and types during compilation. See the
boolean design.
Conditional statements select the first true if/elif body, or the optional
else body. Every condition and body undergoes static checks; arithmetic executes
only on the selected path. Start with the decisions tutorial.
check validates syntax, names, mutability, scopes, primitive types, and arithmetic
without writing program output. It returns zero and remains silent on success.
It evaluates selected loops, declarations, and assignments in fresh local
storage, so reachable unused arithmetic failures are still reported. The Rust
library's scarp::compile only parses and resolves; it does not evaluate arithmetic.
There is no scarp compile CLI command.
tokens checks lexical validity without parsing or executing the file. It prints
one token per line, including decoded string text, one-based line/column ranges,
and half-open UTF-8 byte ranges. For the hello example, the first token is:
2:1..2:6 identifier(print) [26..31]
An end-of-file token is always included. Columns count Unicode scalar values; terminal display widths for combining marks and wide characters can differ. Tabs are expanded to four spaces in error excerpts.
error[E0004]: expected ';', found <eof>
--> example.srp:1:15
|
1 | print("hello")
| ^
= help: use print("text"); or print(1 + 2);
Exit codes are 0 for success, 1 for source, file, or output errors, and 2 for
invalid command-line usage. Diagnostics go to standard error; program output and
token listings go to standard output.
The scarp library exposes lexer::lex, parser::parse, compile,
evaluator::evaluate, interpreter::execute, and run. parse exposes syntax;
compile validates syntax and resolves names into an immutable ResolvedProgram.
check and interpreter::validate also evaluate without an output destination.
evaluator::evaluate preserves an integer result, while evaluate_value returns
an integer/float/string/boolean Value. execute and run validate all
arguments before writing and return RunError. The output destination is explicit, making
execution usable without redirecting process-wide standard output.
For multiple files, use modules::compile_file or an explicit
modules::SourceLoader with modules::compile_with_loader. ModuleProgram
owns its source map and offers separate check/execute methods. Source-string
APIs keep their existing signatures and never load files implicitly. See
module embedding.
let mut output = Vec::new();
scarp::run(r#"print("Hello from Scarp!");"#, &mut output).unwrap();
assert_eq!(output, b"Hello from Scarp!\n");cargo fmt --all -- --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo test --locked --release
cargo build --locked
cargo run --locked -- run examples/hello.srp
cargo run --locked -- tokens examples/hello.srpTests cover source spans, escapes, Unicode, missing punctuation, invalid files,
command-line usage, output failures, arithmetic boundaries, precedence, nesting,
long expression chains, and all shipped examples.
The complete check sequence, including rustdoc, is available as
sh scripts/check.sh --offline or ./scripts/check.ps1 -Offline. See
CONTRIBUTING.md for the development and PR workflow.
While loops and break/continue support iterative computations with explicit
per-call budgets. See loops and limits.
The performance guide provides stage benchmarks and measured execution improvements. C/C++/Rust performance comparisons and native code generation remain future work.
This is a small interpreter. It loads bounded source graphs into memory and reports the first error. Functions are interpreted using heap call frames. It has immutable numerical vectors and tiles and a first source-module system. General-purpose collections, user-defined types, runtime module globals, re-exports, a standard library, a package manager, native code generation and self-hosting require further milestones. It does not execute arbitrary Rust code. The syntax and library API are experimental and may change.
Read the implemented language reference and
architecture notes for precise rules. Runnable programs
in examples/ are paired with .stdout files and checked by the
test suite.
Future work is planned, in this order:
- Module tooling, additional conformance and source navigation.
- Explicit constant-expression and library organization design.
- User-defined types and callable values.
- A compiler backend and developer tooling.
- Domain-specific libraries.
The remaining capabilities require separate milestones. Integer expressions are implemented as specified in the expression design. Integer, finite float, vector, string, and boolean bindings are implemented in this checkout. Read the variable reference and staged variable design. The preparation notes preserve the original module contract; the publication record confirms the released source and checksums. Tensors and native backends require separate integration decisions.
The function integration in PR #41 integrated typed calls, defaults, contracts, and bounded heap frames into main. Beta.3 published that work with CLI resource controls. Beta.2 binaries do not contain functions. Release notes describe immutable snapshots; branch names can move.
Original project code is licensed under the Apache License 2.0.