Skip to main content

InScript - A modern scripting language with generics, ADT enums, coroutines, and more

Project description

๐ŸŽฎ InScript

A modern programming language designed for games โ€” clean syntax, powerful type system, batteries included.

Python 3.10+ License: MIT Tests Version


What is InScript?

InScript is a statically-typed, dynamically-executed scripting language built specifically for game development. It brings Rust-style safety (pattern matching, ADT enums, Result types, generics) with Python-like readability โ€” and runs right out of the box with a single Python file.

// Structs with inheritance and operator overloading
struct Ship {
    x: float   y: float   hp: int

    fn take_damage(amount: int) { self.hp -= amount }
}

struct PlayerShip extends Ship {
    shots: int
    fn fire() -> string {
        self.shots += 1
        return f"๐Ÿ’ฅ Shot #{self.shots}!"
    }
}

// ADT enums with pattern matching
enum Asteroid {
    Small(x: float, y: float)
    Large(x: float, y: float)
}

fn points(a: Asteroid) -> int {
    match a {
        case Small(x, y) { return 30 }
        case Large(x, y) { return 10 }
    }
}

// Generic data structures
struct Stack<T> {
    items: T[]
    fn push(item: T) { self.items.push(item) }
    fn pop() -> T    { return self.items.pop() }
}

// Error propagation
fn accuracy(hits: int, shots: int) -> Result {
    let r = safe_divide(float(hits), float(shots))?
    return Ok(r * 100.0)
}

// Coroutines
fn* spawn_wave(n: int) {
    let i = 0
    while i < n { yield Asteroid.Large(random_int(0,800), 0.0); i += 1 }
}

Feature Overview

Feature Status Notes
Variables (let, const) with type annotations โœ… Type inference supported
Structs with methods โœ… Full OOP
Struct inheritance (extends) โœ… Method dispatch + field inheritance
Interface / Trait system โœ… interface + implements
Operator overloading (fn +()) โœ… All arithmetic + comparison ops
Mixins (with keyword) โœ… Horizontal code reuse
Properties (get/set) โœ… Computed + validated fields
Static methods โœ… static fn on structs
Generics (struct Stack<T>) โœ… Type-erased, multi-param
ADT Enums with data fields โœ… Circle(radius: float)
Pattern matching + guards โœ… case v if v < 10
ADT destructuring โœ… case Circle(r) binds r
Error propagation ? โœ… Ok(v) / Err(e) / Result?
Coroutines / generators โœ… fn* + yield + .next()
Comptime evaluation โœ… comptime { 1024 * 4 }
Pipe operator |> (chainable) โœ… x |> double |> add1
Destructuring โœ… let [a,b] = arr / let {x,y} = p
Spread operator โœ… fn sum(...args) / call(...arr)
Optional chaining โœ… obj?.field?.method()
Nullish coalescing โœ… value ?? "default"
F-strings โœ… f"Hello {name}!"
Multi-line strings โœ… """..."""
Closures / lambdas โœ… |x| x * 2
Async/await syntax โœ…
Labeled break/continue โœ… outer: for ... { break outer }
Built-in math, Vec2, Vec3, Color โœ… Game-ready primitives
REPL โœ… Interactive shell

Quick Start

1. Clone and run (no install needed)

git clone https://github.com/YOUR_USERNAME/inscript.git
cd inscript
python inscript.py examples/asteroid_blaster.ins

2. Try the REPL

python inscript.py --repl
InScript 0.6.0 REPL โ€” type 'exit' or Ctrl+C to quit
>> let x = 42
>> print(f"The answer is {x}")
The answer is 42
>> struct Point { x: float  y: float }
>> let p = Point { x: 3.0, y: 4.0 }
>> print(p.x)
3.0

3. Run any .ins file

python inscript.py mygame.ins

Running in VS Code

Prerequisites

Step-by-step

1. Clone the repo and open in VS Code

git clone https://github.com/YOUR_USERNAME/inscript.git
cd inscript
code .

2. Set Python interpreter

Press Ctrl+Shift+P โ†’ type Python: Select Interpreter โ†’ choose Python 3.10+

3. Open the example program

In the Explorer panel, open examples/asteroid_blaster.ins to browse the code.

4. Create a run task โ€” create .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run InScript file",
      "type": "shell",
      "command": "python",
      "args": ["${workspaceFolder}/inscript.py", "${file}"],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "presentation": {
        "reveal": "always",
        "panel": "shared"
      },
      "problemMatcher": []
    },
    {
      "label": "Run example: Asteroid Blaster",
      "type": "shell",
      "command": "python",
      "args": ["${workspaceFolder}/inscript.py", "examples/asteroid_blaster.ins"],
      "group": "build",
      "presentation": {
        "reveal": "always",
        "panel": "shared"
      },
      "problemMatcher": []
    },
    {
      "label": "InScript REPL",
      "type": "shell",
      "command": "python",
      "args": ["${workspaceFolder}/inscript.py", "--repl"],
      "group": "build",
      "presentation": {
        "reveal": "always",
        "panel": "dedicated"
      },
      "problemMatcher": []
    }
  ]
}

5. Run it!

  • Press Ctrl+Shift+B to run the currently open .ins file
  • Or open Command Palette โ†’ Tasks: Run Task โ†’ choose any task above

Tip: Add this launch.json for F5 debugging too (.vscode/launch.json):

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Run InScript (current file)",
      "type": "debugpy",
      "request": "launch",
      "program": "${workspaceFolder}/inscript.py",
      "args": ["${file}"],
      "console": "integratedTerminal"
    }
  ]
}

Now pressing F5 while editing any .ins file will run it through InScript.


Language Tour

Variables & Types

let x: int = 42
let name = "Ada"          // type inferred
const MAX = comptime { 1024 * 4 }   // compile-time constant = 4096

Functions

fn lerp(a: float, b: float, t: float) -> float {
    return a + (b - a) * t
}

// Closures
let doubled = [1, 2, 3].map(|x| x * 2)

Structs

struct Bullet extends Entity {
    dmg:   int = 10
    speed: float = 600.0

    fn update(dt: float) {
        self.pos += Vec2(0.0, -self.speed * dt)
    }
}

Generics

struct Pair<A, B> {
    first:  A
    second: B
}

let p = Pair<int, string> { first: 1, second: "one" }

ADT Enums + Pattern Matching

enum Shape {
    Circle(radius: float)
    Rectangle(w: float, h: float)
}

fn area(s: Shape) -> float {
    match s {
        case Circle(r)       { return 3.14159 * r * r }
        case Rectangle(w, h) { return w * h }
    }
}

Error Handling

fn load(path: string) -> Result {
    let data = read_file(path)?   // propagates Err upward
    return Ok(data)
}

let result = load("level.json")
let data   = unwrap_or(result, "{}")

Coroutines

fn* enemy_spawner() {
    while true {
        yield Enemy { x: random_int(0, 800), y: -20 }
    }
}

let spawner = enemy_spawner()
let enemy   = spawner.next()

Pipe Operator

fn clamp01(v: float) -> float { return clamp(v, 0.0, 1.0) }
fn to_pct(v: float) -> string { return f"{v * 100.0}%" }

let display = raw_value |> clamp01 |> to_pct
// โ†’ "73.5%"

Project Structure

inscript/
โ”œโ”€โ”€ inscript.py          โ† Entry point (run files, REPL, flags)
โ”œโ”€โ”€ lexer.py             โ† Tokenizer
โ”œโ”€โ”€ parser.py            โ† Recursive-descent parser โ†’ AST
โ”œโ”€โ”€ ast_nodes.py         โ† All AST node dataclasses
โ”œโ”€โ”€ interpreter.py       โ† Tree-walk interpreter (122 tests)
โ”œโ”€โ”€ analyzer.py          โ† Static type analyzer
โ”œโ”€โ”€ environment.py       โ† Scope / variable resolution
โ”œโ”€โ”€ errors.py            โ† Error + signal classes
โ”œโ”€โ”€ stdlib.py            โ† Standard library
โ”œโ”€โ”€ stdlib_values.py     โ† Runtime value types (InScriptRange, etc.)
โ”œโ”€โ”€ repl.py              โ† Interactive REPL
โ”œโ”€โ”€ setup.py             โ† PyPI packaging
โ”œโ”€โ”€ examples/
โ”‚   โ””โ”€โ”€ asteroid_blaster.ins   โ† Full demo program
โ””โ”€โ”€ tests/
    โ”œโ”€โ”€ test_interpreter.py    โ† 122 runtime tests
    โ”œโ”€โ”€ test_parser.py
    โ”œโ”€โ”€ test_lexer.py
    โ”œโ”€โ”€ test_analyzer.py
    โ””โ”€โ”€ test_stdlib.py

Testing

# Run all interpreter tests (122 tests)
python test_interpreter.py

# Run parser tests
python test_parser.py

# Run lexer tests
python test_lexer.py

Expected output:

=================================================================
  Phase 4 Final Results
=================================================================
  122 passed, 0 failed out of 122 tests
=================================================================

CLI Reference

python inscript.py <file.ins>          # Run a file
python inscript.py --repl             # Interactive REPL
python inscript.py --check <file.ins> # Type-check only (no run)
python inscript.py --tokens <file.ins># Print lexer tokens
python inscript.py --ast <file.ins>   # Print the AST
python inscript.py --version          # Print version

Roadmap

  • Union / intersection types (Shape = Circle | Rectangle)
  • Abstract methods (abstract fn update())
  • Macro / metaprogramming system
  • SIMD vector types (float32x4)
  • LSP VS Code extension (syntax highlighting + completions)
  • PyPI package (pip install inscript-lang)

License

MIT โ€” see LICENSE


Built with โค๏ธ and Python ยท InScript 0.6.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inscript_lang-0.6.0.tar.gz (76.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inscript_lang-0.6.0-py3-none-any.whl (75.2 kB view details)

Uploaded Python 3

File details

Details for the file inscript_lang-0.6.0.tar.gz.

File metadata

  • Download URL: inscript_lang-0.6.0.tar.gz
  • Upload date:
  • Size: 76.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for inscript_lang-0.6.0.tar.gz
Algorithm Hash digest
SHA256 f0666a9e44fbace9fafc55c3611a3b840d0a16ab46be0cf85ef8202f41fadcde
MD5 b32dc6bb9780d27419d7c47c849bec69
BLAKE2b-256 08225afefd3129cbd1eda2af154eeb9a9b75cc92e9926a21c3627c5f68c03fe9

See more details on using hashes here.

File details

Details for the file inscript_lang-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: inscript_lang-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 75.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for inscript_lang-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2460617884e09a411dd90eb830dc0579b96d29e530d8b246645fb8931e08d70a
MD5 82fd86692899f4376aaf239e450bcfe3
BLAKE2b-256 b612dce7a060c59ec16fcc6edee16a5c2ed12f26cb7f962557b0ad384c29d2db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page