Language Specification

This page summarizes the ScarScript v1 specification in a browsable reference. For installation, see Get Started; for practical examples, start with the syntax guide.

Source files and names

ScarScript source is UTF-8 text and conventionally uses the .scar extension.

Language keywords include:

val mut const if else for in and or true false map str int bool any dec func return

Built-in names such as print, log, math, file, sys, and time cannot be redeclared. Go keywords are also reserved because ScarScript generates Go source. Names are case-sensitive, start with a letter or underscore, and may contain letters, digits, or underscores; user declarations beginning with _ are prohibited.

Types

Primitive types are str, int, bool, dec, and any. The void type denotes a function with no return value.

Composite types include arrays (str[]), maps (map[str: int]), and tuples for function return values ((int, bool)). Function-value types are inferred rather than written as annotations.

Assignments require compatible types. Exact matches and widening to any are supported. Integer literals can be used where dec is expected, but an int variable is not implicitly widened for assignment. Mixed int and dec arithmetic promotes to dec.

Declarations

val name: str = "Ada" mut count: int = 0 const LIMIT: int = 10 val inferred = 42

val is immutable, mut is mutable, and const declares a compile-time constant. Constants are limited to str, int, and bool, and must have literal initializers (or a negative integer literal).

Tuple-returning calls may initialize more than one val or mut binding:

val quotient, valid = divide(10, 2)

The right-hand side must be a single call that returns a tuple. This form does not support const or a type annotation.

Expressions and operators

From highest to lowest, expression precedence is:

  1. Primary expressions: literals, identifiers, calls, indexing, member access, and parentheses.
  2. Unary - and !.
  3. Multiplication, division, and remainder: *, /, %.
  4. Addition and subtraction: +, -.
  5. Range: ...
  6. Ordering comparisons: <, >, <=, >=.
  7. Equality: ==, !=.
  8. Logical AND: and.
  9. Logical OR and fallback: or.
  10. Ternary: ? :.

Arithmetic works on compatible numeric values; % requires integers. + also concatenates two strings. Comparisons produce bool; mixed numeric comparisons promote to dec. and short-circuits. or is boolean OR for two booleans and also provides a zero-value fallback for supported types (or a type-assertion fallback when its left side is any).

Ternary expressions use condition ? whenTrue : whenFalse; both branches must have the same type.

Calls, indexing, and member access can be combined:

print("hello") math.sqrt(16) items[0] scores.ada // string-key map access shorthand

Statements and control flow

Only calls can be used as expression statements. Assignment is allowed only for mutable bindings. Increment and decrement operators (++, --) work with integers.

Blocks create a local scope. Conditions in if / else if / else require braces and must evaluate to bool; parentheses around the condition are optional.

The universal for statement supports:

for value in values { ... } // array elements for index, value in values { ... } // array index and element for key, value in records { ... } // map key and value for condition { ... } // while-style loop

The supplied language specification describes ranges as integer iteration, while the generated syntax guide demonstrates 0..5 as end-exclusive. The source materials disagree about whether the range endpoint is included; check the compiler behavior for your installed release before depending on endpoint handling.

return may return no value, one value, or the values of a tuple-returning function. Non-void functions must return on every path; statements after a return in the same block are unreachable.

Functions and scope

Named functions are top-level declarations. Their parameters and local declarations form an isolated scope; recursion, mutual recursion, and forward references are supported.

Anonymous functions are assigned to val or mut declarations and can capture variables from their lexical scope. In v1.0.1, top-level const and literal-initialized val values are available to named functions; mutable globals and values initialized by non-literals are not.

Built-in modules

The module names math, file, sys, and time are reserved. Call module functions directly; the compiler includes required Go imports in generated code. See the module reference for signatures.

Diagnostics

Compile errors use this format:

file.scar:LINE:COL: error: message

Common diagnostics include type mismatches, invalid argument counts or types, missing returns, unreachable statements, undefined identifiers, redeclarations, and misuse of reserved names.

Compilation model

ScarScript compiles through a lexer, parser, static checker, and Go code generator. The generated Go is formatted and then run or built with Go. scar run executes a program; scar build produces a native binary. See the CLI reference.