G-Lang logo
Download v0.8.0 Documentation View Source
v0.8.0 — MIT License

G-Lang
C evolved.

A transpiler-based extension of C. Write modern, expressive code — default parameters, overloading, defer, modules, a math library — and compile with any C compiler. No runtime. No bloat. No OOP.

// World.g — entity movement
#module World
#import GMath

struct Entity {
  Vec2 pos;
  float speed = 1.0f;
  int   active = 1;
};

void entity_update(Entity^ e, float dt) {
  defer { log_frame(e); }
  Vec2 vel = GMath.vec2(1.0f, 0.0f);
  GMath.vec2_scale_ip(&vel, e->speed * dt);
  GMath.vec2_add_ip(&e->pos, vel);
}
Default Parameters
Function Overloading
defer
Module System
Struct Defaults
Struct Embedding
Error-as-value
Standard Library
Full Toolchain
Zero Defaults

Installation

G-Lang requires GCC (or Clang) to compile your projects, and optionally GDB + VSCodium for debugging. The transpiler itself is a pre-built native binary — no Python needed to run it.

git clone https://gitlab.com/g-lang-group/G-Lang-project.git
cd G-Lang-project
bash setup.sh

setup.sh builds guild from source, installs it to ~/.local/bin/, and optionally installs the VSCodium extension.

Quick Start

Create a .g file

// src/hello.g
#module Hello

void greet(char^ name = "world") {
  printf("Hello, %s!\n", name);
}

Build it

Put your .g files in src/ and run guild build. Guild auto-discovers all .g files, compiles them, and cleans up the intermediate C files automatically.

guild build
# transpiles src/*.g → build/, compiles, cleans C files

guild build --release
# optimized build, binary goes to release/

guild run
# build and run in one step

Transpile only (no compile)

guild transpile hello.g -o out/
# outputs out/Hello.c and out/Hello.h

Full project with guild.toml

# guild.toml — directory sources auto-discover all .g files
name = "my_game"

[build]
sources = ["src/", "npc/", "main.c"]
libs = ["SDL2"]
flags = ["-Wall"]
guild build
guild build --release
guild run

Shared Modules

Multiple .g files can declare the same #module Name. This lets you split a large module across files — useful for NPC systems, rendering layers, or any subsystem that grows too large for one file.

// npc/base.g
#module NPC
void spawn(int id) { ... }

// npc/pathfind.g
#module NPC
void move_to(int x, int y) { ... }

// npc/combat.g
#module NPC
int attack(int target_id) { ... }

Guild generates NPC_base.c, NPC_pathfind.c, NPC_combat.c, and a single merged NPC.h containing all prototypes. Consumers just #import NPC as normal — the split is invisible from the outside.

Multi-Project Builds

For layered architectures (game → engine → graphics), a single guild.toml can orchestrate multiple sub-projects with explicit dependency ordering. Guild builds bottom-up and makes each layer's headers available to layers above it.

name = "hegemony"
projects = ["graphics", "engine", "game"]

[project.graphics]
sources = ["graphics/"]
libs = ["SDL2"]

[project.engine]
depends = ["graphics"]
sources = ["engine/"]

[project.game]
depends = ["engine"]
sources = ["game/", "npc/"]

Each project can declare its own sources, libs, and flags. The depends key controls build order and include paths — a project's generated headers are automatically available to everything that depends on it.

Naming Conventions

ContextName
LanguageG / G-Lang
File extension.g
Transpiler binaryguild
Build commandguild build / guild run
Transpile onlyguild transpile
Source directorysrc/ (default, auto-discovered)
Generated C outputbuild/ (auto-cleaned after compile)
Debug binary. (project root)
Release binaryrelease/

Build Flags

FlagEffect
--release-O2 -DNDEBUG, binary goes to release/
--cleanwipe build dirs before building
--keep-cdon't delete generated .c files after compile
--transpile-onlyskip the compile step
--flatdump everything in cwd (no src/build layout)
--src <dir>override source directory
--out <dir>override C output directory
--bin <path>override binary output path

Precedence: CLI flag → guild.toml → built-in default.

Key Features

Default Parameters

int add(int a=5, int b=3) {
  int result;
  result = a + b;
  return result;
}

Function Overloading

float scale(float v, float s) { ... }
Vec2  scale(Vec2 v, float s) { ... }
// Rewritten at transpile time — zero runtime cost

defer

void load_texture() {
  FILE* f = fopen("tex.png", "rb");
  defer { fclose(f); }
  // ... work with f ...
}

Module System

#module Physics

// In another file:
#import Physics as ph
ph.apply_force(&body, force);

G-Lang in practice.

Real G code from the test suite — every feature shown, compiled and verified against 12 passing test checks.

Feature showcase — Tests.g

The full feature test file. Each section exercises a different G-Lang feature end-to-end.

Tests.g G
#module Tests

#include <stdio.h>
#include <string.h>
#import TestMath

// ── Feature 1: Default zero initialisation ───────────────────────────────────

void test_zero_init() {
    int   i;
    float f;
    char  c;
    int^  p;
    printf("[zero_init] int=%d float=%.1f char=%d pointer=%s\n",
           i, f, c, p == NULL ? "NULL" : "non-null");
}

// ── Feature 2: ^ pointer declaration ────────────────────────────────────────

void test_pointer_syntax() {
    int value = 42;
    int^ ptr = &value;
    printf("[pointer] value via deref=%d\n", *ptr);
}

// ── Feature 3: Default parameters ────────────────────────────────────────────

int add(int a=10, int b=20) {
    int result;
    result = a + b;
    return result;
}

// ── Feature 4: Function overloading ──────────────────────────────────────────

int describe(int x) {
    printf("[overload] int: %d\n", x);
    return x;
}

float describe(float x) {
    printf("[overload] float: %.2f\n", x);
    return x;
}

double describe(double x) {
    printf("[overload] double: %.4f\n", x);
    return x;
}

int sum(int a, int b) { int r; r = a+b; return r; }
int sum(int a, int b, int c) { int r; r = a+b+c; return r; }
int sum(int a, int b, int c, int d) { int r; r = a+b+c+d; return r; }
float sum(float a, float b) { float r; r = a+b; return r; }

// ── Feature 4b: Dot syntax — cross-module calls ──────────────────────────────

int test_dot_syntax() {
    int   sq_i = TestMath.square(5);
    float sq_f = TestMath.square(3.0f);
    int   add2 = TestMath.add(10, 20);
    int   add3 = TestMath.add(10, 20, 30);
    printf("[module] square(5)=%d square(3.0f)=%.1f add(10,20)=%d add(10,20,30)=%d\n",
           sq_i, sq_f, add2, add3);
    int total; total = sq_i + add2 + add3; return total;
}

// ── Feature 5: defer ─────────────────────────────────────────────────────────

void test_defer() {
    printf("[defer] start\n");
    defer { printf("[defer] third (LIFO 1)\n"); }
    defer { printf("[defer] second (LIFO 2)\n"); }
    defer { printf("[defer] first (LIFO 3)\n"); }
    printf("[defer] end of body — defers fire now:\n");
}

void test_defer_with_return(int early) {
    defer { printf("[defer_return] cleanup always runs\n"); }
    if (early) {
        printf("[defer_return] early return path\n");
        return;
    }
    printf("[defer_return] normal return path\n");
}

// ── Feature 6: Error-as-value ─────────────────────────────────────────────────

int! safe_divide(int a, int b) {
    if (b == 0) return error(1, "division by zero");
    return a / b;
}

void test_error() {
    // else {} handles errors inline
    int result = safe_divide(10, 2) else {
        printf("error %d: %s\n", err.code, err.msg);
        result = 0;
    };
    printf("[error] 10/2=%d\n", result);
}

// ── Feature 10: undefined keyword ────────────────────────────────────────────

void test_undefined() {
    int safe;
    int risky = undefined;
    safe = 100; risky = 200;
    printf("[undefined] safe=%d risky=%d\n", safe, risky);
}

// ── Feature 11: Struct defaults + auto typedef ───────────────────────────────

struct Player {
    float height = 5.10f;
    float weight = 180.0f;
    int   hp     = 100;
    int   mana   = 50;
    int   score;
};

// ── Feature 12: using keyword — struct embedding ─────────────────────────────

struct Transform {
    float x        = 0.0f;
    float y        = 0.0f;
    float rotation = 0.0f;
};

struct Entity {
    int   id     = 0;
    int   active = 1;
    using Transform transform;
};

void print_entity(Entity e) {
    printf("[using] id=%d active=%d x=%.2f y=%.2f rotation=%.2f\n",
           e.id, e.active, e.x, e.y, e.rotation);
}

Building with guild

The simplest workflow: put .g files in src/, run guild build. Guild auto-discovers all .g files, transpiles them, compiles, and cleans up the intermediate C files. The binary lands in the project root for debug builds and release/ for release builds.

guild — smart defaults build
# debug build — looks in src/, binary in ./
$ guild build

# optimized — binary goes to release/
$ guild build --release

# build and run in one step
$ guild run

# transpile only, no compile
$ guild transpile src/World.g -o out/
guild — override defaults flags
# keep generated C files (default: cleaned)
$ guild build --keep-c

# override source / output dirs
$ guild build --src lib --out tmp

# dump everything in cwd (no src/build layout)
$ guild build --flat

# wipe build dirs then rebuild
$ guild build --clean

Full project with guild.toml

For multi-file projects, drop a guild.toml in the project root. Explicit sources lists override auto-discovery. Mix .g and .c files freely.

guild.toml TOML
# Project metadata
name    = "my_game"
version = "0.1.0"

[build]
# Directory entries scan recursively for .g files
sources = ["src/", "npc/"]

# Explicit file list also works — or mix both
# sources = ["Entity.g", "npc/", "main.c"]

# Link against any C library
libs    = ["SDL2", "m"]

# Pass extra flags to gcc
flags   = ["-Wall", "-Wextra"]

# Optional overrides (all have smart defaults)
# src_dir  = "src"      # where to find .g files (if no sources list)
# out_dir  = "build"    # where generated .c files go (auto-cleaned)
# bin_dir  = "."        # debug binary location
# rel_dir  = "release"  # release binary location
# keep_c   = false      # set true to keep generated .c files
# cc       = "clang"    # override compiler (default: gcc)
guild — common commands build system
# debug build (default)
$ guild build

# optimized release build
$ guild build --release

# build and run immediately
$ guild run

# release build and run
$ guild run --release

# clean generated files
$ guild build --clean
guild — what it does pipeline
# guild build runs this pipeline:
#
# 1. find guild.toml (searches upward)
# 2. discover *.g in src/ (or use sources list)
# 3. transpile each .g file → build/
# 4. compile all .c files with gcc
# 5. link into the named executable
# 6. auto-clean generated .c files
#
# debug builds auto-add -g for GDB
# .g breakpoints work natively via #line
#
# release builds add -O2 -DNDEBUG
v0.8.0 — Latest Release

Download G-Lang

The transpiler is now a native C binary — no Python required to run it. Linux x86-64. GCC required to compile your G projects.

VSCodium Extension

Editor integration for .g files

  • Syntax highlighting
  • Autocomplete — functions, structs, modules
  • Hover signatures + default param values
  • Go-to-definition across modules
  • Requires Python 3 + pygls
Download Extension v0.8.0

Install via editors/vscode/install.sh

total downloads & clones

Or clone the full source — includes standard library, test suite, and setup script:

$ git clone https://gitlab.com/g-lang-group/G-Lang-project.git
$ cd G-Lang-project && bash setup.sh

Looking for the original Python toolchain? G-Lang-legacy ↗

What you need

Required

Linux x86-64

The pre-built guild binary targets Linux x86-64. Windows and macOS users can build from source — see GETTING_STARTED.md in the repo.

Required

GCC / Clang

Any C11 compiler. GCC is the default; set cc = "clang" in guild.toml to switch.

Optional

GDB + VSCodium

For source-level debugging. Set breakpoints in .g files, step through, inspect variables. Works via standard #line directives — no custom adapter needed.

Optional

Python 3 + pygls

Only needed for the VSCodium language server (autocomplete, hover, go-to-def). Not required to use the transpiler itself.

Why G-Lang exists.

C is the language games are built in. From id Software's Quake to modern indie engines, C's performance, predictability, and direct hardware access make it the pragmatic choice. But C has papercuts — small, daily frustrations that accumulate over a project.

G-Lang fixes the papercuts. It's a transpiler that converts G source files to standard C before compilation. The output is readable, debuggable C you can inspect and compile with any C toolchain.

G adds exactly what developers — game developers especially — reach for constantly: default parameters, function overloading, defer for deterministic cleanup, a module system, and a math library that pairs directly with OpenGL, Vulkan, and SDL.

Philosophy

Status

G-Lang is at v0.8.0. The transpiler has been fully rewritten in C and the build system has smart defaults — drop .g files in src/, run guild build, and you get a binary with intermediate C files cleaned up automatically. Multiple .g files can share a #module name and are merged into a single header. Multi-project guild.toml handles layered architectures like game → engine → graphics in one build command. Source-level debugging works via standard #line directives in any DWARF-aware tool.

It has not yet been battle-tested in a shipped game. 1.0 means a real game ships with it. That's the milestone.

Author

Built by Garrett Gaston. Source on GitLab. MIT License.

Get in touch.

Found a bug? Have a feature idea? Building something with G-Lang? There are two ways to reach us depending on what you need.

Report a Bug

Found something broken? Open a GitLab issue — it gets tracked, prioritized, and fixed. GitLab account required.

Open an Issue ↗

Browse Issues

See what's already been reported, vote on features, or pick up something to contribute to.

View All Issues ↗

General feedback

Questions, ideas, or just want to say you're using G-Lang — use the form below. Goes directly to dev@g-lang.io.

Send a message

Message sent — thanks for the feedback!