https://github.com/buzz-language/buzz Skip to content Toggle navigation Sign up * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code + Explore + All features + Documentation + GitHub Skills + Blog * Solutions + For + Enterprise + Teams + Startups + Compare all + By Solution + CI/CD & Automation + DevOps + DevSecOps + Case Studies + Customer Stories + Resources * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles + Repositories + Topics + Trending + Collections * Pricing [ ] * # In this repository All GitHub | Jump to | * No suggested jump to results * # In this repository All GitHub | Jump to | * # In this organization All GitHub | Jump to | * # In this repository All GitHub | Jump to | Sign in Sign up {{ message }} buzz-language / buzz Public * * Notifications * Fork 4 * Star 272 buzz, A small/lightweight typed scripting language (in development) License MIT license 272 stars 4 forks Star Notifications * Code * Issues 41 * Pull requests 1 * Actions * Projects 0 * Security * Insights More * Code * Issues * Pull requests * Actions * Projects * Security * Insights buzz-language/buzz This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. main Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags Name already in use A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Cancel Create 4 branches 1 tag Code * Clone HTTPS GitHub CLI [https://github.com/b] Use Git or checkout with SVN using the web URL. [gh repo clone buzz-l] Work fast with our official CLI. Learn more. * Open with GitHub Desktop * Download ZIP Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching Xcode If nothing happens, download Xcode and try again. Launching Visual Studio Code Your codespace will open once ready. There was a problem preparing your codespace, please try again. Latest commit @naltun naltun Fix arithmetic error in README example (#99) ... cce8a52 Nov 21, 2022 Fix arithmetic error in README example (#99) cce8a52 Git stats * 515 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .github .vscode doc lib src tests tools .gitignore .gitmodules LICENSE README.md build.zig buzz.code-workspace example.png logo.png View code [ ] buzz Goals Progress How to build Requirements Steps Quick tour Types and variables Operators Optionals Functions Generics Enums Control flow foreach Objects Anonymous objects Protocols Errors Import/Export Fibers Call C/Zig code README.md buzz buzz A small/lightweight typed scripting language written in Zig buzz code example Goals * Small in size and complexity (just a bit more than Lua though) * Strict typing * Unambiguous * No nonsense coercion * Fibers * Tooling + Generate doc from docblocks (in progress) + LSP (in progress) + Debugger and DAP + TextMate syntax Progress We're not far from completing miletone 0.1.0. As writing buzz code is the best way of finding bugs, we implement a lot of features of the next milestones too. How to build Requirements * Since this is built with Zig, you should be able to build buzz on a wide variety of architectures even though this has only be tested on x86. * Linux or macOS (not much work is needed to make it work on Windows) * libpcre (not libpcre2) * libc on Linux * zig master Steps 1. Clone project: git clone https://github.com/buzz-language/buzz 2. Checkout submodules: git submodule update --init 3. Build it: zig build -Drelease-safe 4. Add to your shell rc: export BUZZ_PATH="/path/to/buzz/dist" export PATH="$BUZZ_PATH:$PATH" 5. Have fun: buzz Additionnally, install the VS Code extension to get syntax highlighting. If you don't use VS Code but your editor supports TextMate grammar files, you can use that. Quick tour Note: You can also take a look at tests/ for more examples. * Types and variables * Operators * Functions * Enums * Control flow * Objects * Protocols * Errors * Import/Export * Fibers * Call C/Zig code Types and variables | Basic types bool aBoolean = true; | Immutable sequence of bytes str aString = "hello world"; str multiline = ` i'm on several lines yes `; | Numbers are either internally i64 or f64 and are coerced from one to the other as needed num aNumber = 23; aNumber = 0b110; aNumber = 0xA12F; | A PCRE regex pat aPattern = _hello [a-z]+_; | Userdata are pointers to foreign data wrapped inside a buzz obj ud userdata = GetSomeForeignData(); | A constant const num pi = 3.14; | Data structures [num] aListOfNumbers = [1, 2, 3]; | Keys and values can be of any type {str, num} aMap = { "one": 1, "two": 2, "three": 3, }; Operators | Comparison 12 == 12; 12 != 13; 12 >= 12; 12 <= 12; 12 > 11; 12 < 13; | Arithmetic 12 + 12 == 24; 12 - 12 == 0; 12 * 12 == 144; 12 / 12 == 1; 12 % 12 == 0; | Logical 12 > 3 and 5 < 12; 12 > 3 or 12 < 5; | String "hello " + "world" == "hello world"; "hello" == "hello"; | Bitwise 15 << 3 == 120; | shift left 15 >> 3 == 1; | shift right 12 & 23 == 4 | and 15 ^ 3 == 12; | xor 15 \ 3 == 15; | or ~15 == -16; | not Optionals str? aStringOrNull = "hello"; | Null coalescing operator is `??` str unwrapped = aStringOrNull ?? "default value" | Force unwrapping with `!` str unwrapped = aStringOrNull!; | Graceful unwrapping [num]? optList = null; print(optList?.len()); | -> null | If unwrap if (aStringOrNull -> aString) { print("{aString} is not null"); } else { print("aString was null"); } Functions fun sayHiTo(str name, str? lastName, num age) > str { | Interpolation with `{}` return "Hi {name} {lastName ?? ""}!" } | Same could be an arrow function fun sayHiTo(str name, str? lastName, num age) > str -> "Hi {name} {lastName ?? ""}!" When called, only the first argument name of a function can be omitted, order is not required: sayHiTo("Joe", age: 35, lastName: "Doe"); | -> "Hi Joe Doe!" Functions are first-class citizens: Function() fn = fun () > void -> print("hello world"); | Arrow function fn(); | -> "hello world" Generics fun countMap(, {K, V} map) > num { return map.size(); } {str, num} map = { "one": 1, "two": 2, "three": 3, }; countMap(, map) == 3; Enums | Enums can have number or string values enum Natural { zero, one, two, } Natural.zero.value == 0; | Values must either be implicit or be all defined enum(num) NumEnum { three = 3, four = 4, five = 5, } enum(str) Country { usa = "United States of America", uk = "United Kingdoms", fr = "France", } | To get the value associated with a enum case print(Country.usa.value); | -> "United States of America" enum(str) Locale { fr, en, it, } Locale.fr.value == "fr"; | Create enum instance from its value Locale? locale = Locale("fr"); locale == Locale.fr Control flow | The usual if (someCondition) { | ... } else if (anotherCondition) { | ... } else { | ... } num i = 0; while (i < 10) { i = i + 1; } num j = 10; do { j = j - 1; } until (j == 0) for (num i = 0; i < 10; i = i + 1) { | ... break; } foreach foreach can iterate over most data structures: foreach (SomeEnum case in SomeEnum) { | ... } foreach (num i, str value in listOfStrings) { | ... } foreach (str key, num value in aMap) { | ... } foreach (num i, str char in aString) { | ... } fib fibonnaciFib = &fibonnaci(10); foreach (num value in fibonnaciFib) { | ... } Objects An object is like a class except it can't be inherited from and can't inherit from anything: object Person { static population = 0; str name = "Joe", | Fields can have default values num age = 35, | Method fun sayHello() > void { print("Hello {this.name}"); } | Object don't have constructor but you can implement one with a static method static init(str name, num age) > Person { Person.population = Person.population + 1; return Person { name = name, age = age, }; } } Anonymous objects | Anonymous objects don't have methods, static fields or default values fun getInfo() > obj{ str name, num age } { return .{ name = "Joe", age = 36, }; } | ... obj{ str name, num age } info = getInfo(); Protocols A protocol defines a set of methods. Objects can conform to any number of them: protocol Translatable { fun translate(dx: num, dy: num) > void; } protocol Printable { fun print() > void; } object(Translatable, Printable) Point { num x, num y, fun translate(dx: num, dy: num) > void { this.x = this.x + dx; this.y = this.y + dy; } fun print() > void { print("Point ({this.x}, {this.y})"); } } object(Printable) Line { Point start, Point end, fun print() > void { print("Line ({this.start.x}, {this.start.y}) ({this.end.x}, {this.end.y})"); } } | ... [Printable] elements = [ Point{ x = 0, y = 0 }, Line{ start = Point{ x = 10, y = 10 }, end = Point{ x = 15, y = 12 }, }, ]; foreach (num i, Printable element in elements) { element.print(); } Errors Functions must specify which error they can raise with !> type1, type2, .... Error can't be raised in the global scope. test functions ignore errors. enum(str) MyErrors { failed = "Something failed", bad = "Something bad", ohno = "Oh no!", } enum(str) OtherErrors { failed = "Something failed", bad = "Something bad", ohno = "Oh no!", } fun willFail() > num !> MyErrors, OtherErrors, str { num random = rand(); if (random == 1) { throw MyErrors.failed; } else if (random == 0) { throw OtherErrors.failed; } throw "something else"; return 0; } | Use default value in case of any error num result = willFail() catch 0; | Try catch works as you would expect try { willFail(); } catch (str error) { print("Caught error {error}"); } catch { print("Catches everything"); } | Throwing an object instance with a `message` field will print the message throw .{ message = "Something's wrong" } | -> Error: Something's wrong throw SomeObject{ number = 12 } | -> Error: object instance 0x1feb12 `SomeObject` Import/Export | hello.buzz | Import std lib import "lib/std"; fun sayHello() > void { print("Hello world!"); } | Make it visible when imported export sayHello; | main.buzz import "hello"; fun main([str] args) > void { sayHello(); } Fibers Similar to Lua's coroutines. Buzz's fibers have their own state and stack and can be switched in and out from. Fibers can yield from within any call depth. Any function can be wrapped in a fiber. Unlike Lua, yield are evaluated and dismissed if a function is not called within a fiber and do not raise an error. resolve allows to run a fiber until completion without stopping for any yield. It can be called after the fiber is over in order to get the wrapped function return value. | Returns a string, yields numbers | Always yields an optional type because null is returned if you resume a terminated fiber fun count(num n) > str > num? { for (num i = 0; i < n; i = i + 1) { | If the function is not called in a fiber, yields are evaluated and dismissed | Otherwise the value is returned as `resume` result yield i; } return "Counting is done!"; } fun main([str] args) > void { | Wraps the call to `count` in a fiber, however the fiber is not started until a `resolve` or `resume` instruction fib counter = &count(10); num sum = 0; while (!counter.over()) { | resume returns null if nothing was yielded and/or fiber is over sum = sum + resume counter ?? 0; } assert(resolve counter == "Counting is done!", message: "resolve returns fiber return value"); } Call C/Zig code First define the buzz interface. The extern keyword means that buzz we'll look for a dynamic library named libmylib.dylib (only dylib right now): | mylib.buzz extern fun assert(bool condition, str message) > void Then implement it in Zig or C using the buzz_api: // buzz_mylib.zig const std = @import("std"); const api = @import("buzz_api.zig"); // We have to respect C ABI export fn assert(vm: *api.VM) c_int { var condition: bool = vm.bz_peek(1).bz_valueToBool(); if (!condition) { vm.bz_throw(vm.bz_peek(0)); } return 0; } Build a dynamic library for it (TODO: instructions for this) and you can use it in your buzz code: | main.buzz import "mylib" fun main([str] args) > void { assert(1 + 1 == 2, message: "Congrats on doing math!"); } Native functions have all the same signature fn myfunction(vm: *VM) bool. If values must be returned, push them on the stack and return true. zig About buzz, A small/lightweight typed scripting language (in development) Topics language zig Resources Readme License MIT license Stars 272 stars Watchers 8 watching Forks 4 forks Releases 1 tags Sponsor this project Sponsor Learn more about GitHub Sponsors Packages 0 No packages published Contributors 2 * * Languages * Zig 98.9% * Other 1.1% Footer (c) 2022 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time. You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.