Daniele Scasciafratte

Amber Lang

Easily write Bash with a transpiler

Daniele Scasciafratte / @Mte90Net

Daniele Scasciafratte

  • Co Founder/CTO Codeat
  • Open Source Addicted
  • Mozillian & Mozilla TechSpeaker/Reps (former)
  • WordPress Core Contributor (former)
  • Italian Linux Society council member
  • Amber Lang Co-Maintainer
  • Book Author: "Contribute to Open Source: the right way"

Bash

Bash, short for Bourne-Again SHell, is a shell program and command language supported by the Free Software Foundation and first developed for the GNU Project by Brian Fox. Designed as a 100% free software alternative for the Bourne shell, it was initially released in 1989.
https://en.wikipedia.org/wiki/Bash_(Unix_shell)

Bash

Since then, Bash has become by far the most popular shell among users of Linux, becoming the default interactive shell on that operating system's various distributions and on Apple's macOS releases before Catalina in October 2019. Bash has also been ported to Microsoft Windows and distributed with Cygwin and MinGW, to DOS by the DJGPP project and to Android via various terminal emulation applications.
https://en.wikipedia.org/wiki/Bash_(Unix_shell)

Bash Pro/Cons

✔️ It is everywhere

✔️ Already installed (except for the commands)

✔️ Standard for Linux scripts

❌ Unique (and strange) syntax

❌ It is easy to follow wrong practices

✔️/❌ Linux commands knowledge required

❌ Time consuming to write a (complex) script

Amber Lang


amber-lang.com

Alpha Status

We are working hard in a lot of areas: documentation, package releases, syntax, community etc.

This means that there could be breaking changes or temporary feature implementations.

Amber


import * from "std/env"
fun example(value:Num = 1) {
    if 1 > 0 {
        let numbers = [value, value]
        let sum = 0
        loop i in numbers {
            sum += numbers[i]
        }
        echo "it's " + "me"
        return sum
    }
    fail 1
}
echo example(1) failed {
    echo "What???"
    is_command("echo")
}
					

Bash


example__0_v0() {
    local value=$1
    if [ "$(( 1 > 0 ))" != 0 ]; then
        numbers_0=("${value}" "${value}")
        sum_1=0
        for i_2 in "${numbers_0[@]}"; do
            sum_1="$(( ${sum_1} + \
                ${numbers_0[${i_2}]} ))"
        done
        echo "it's ""me"
        ret_example0_v0="${sum_1}"
        return 0
    fi
    ret_example0_v0=''
    return 1
}
example__0_v0 1
__status=$?
if [ "${__status}" != 0 ]; then
    echo "What???"
fi
ret_example0_v0__14_6="${ret_example0_v0}"
echo "${ret_example0_v0__14_6}"
					

Real Amber Script (example)


#!/usr/bin/env amber
import { split, text_contains } from "std/text"
import { file_write, file_append, dir_exists, file_exists, dir_create } from "std/fs"
let path = "/tmp/amber-sc-tests"
if (not dir_exists(path)) {
    dir_create(path) failed {
        echo "Failed to create directory {path}"
        exit 1
    }
}
trust $ cp -r "src/tests/stdlib/" {path} $
let report = "{path}/report.txt"
file_write(report, "Report for Shellcheck") failed {
    echo "Failed to write report file"
    exit 1
}
let output = ""
let stdtests = trust $ /usr/bin/ls "src/tests/stdlib/" $
let stdlib = split(stdtests, "\n")
for v in stdlib {
    if not text_contains(v, ".txt") and file_exists("src/tests/stdlib/{v}") {
        echo "Generating Bash script for test {v}"
        trust $ ./target/debug/amber build "src/tests/stdlib/{v}" "{path}/{v}.sh" $
        output = $ shellcheck "{path}/{v}.sh" $ exited(code) {
            if code != 0 {
                echo "Shellcheck found something!"
                file_append(report, "\n--- Issues in {v} ---\n{output}") failed {
                    echo "Failed to append to report"
                }
            }
        }
    }
}
					
https://docs.amber-lang.com/by_example/sh_tester

Real Amber Script


import { make_executable } from "std/fs"
import { download } from "std/http"
import { is_root } from "std/env"
import { contains } from "std/text"

if not is_root() {
    echo("This script requires root permissions!")
    exit(1)
}

[..]

fun download_to_bin(download_url, binary, packed_file) {
    if silent file_download(download_url, packed_file)? {
        trust {
            if text_contains(packed_file, "tar.gz") {
                $tar -zxvf "./{packed_file}" -C ./ > /dev/null 2>&1$
                trust mv("./{binary}", "/usr/local/bin")
            } else {
                $gunzip -c "{packed_file}" > "/usr/local/bin/{binary}"$
            }
            $rm "./{packed_file}"$
        }
        file_chmod("/usr/local/bin/{binary}", "+x")?
    } else {
        echo("Download for {binary} at {download_url} failed")
        exit(1)
    }
}
					
https://docs.amber-lang.com/by_example/lsp_installer

Features

  • Integrates (if found): bshchk (runtime Bash dependency checker)
  • Support for Bash 3.2-5.3 (Soon Zsh too!)
  • Syntax easier to remember
  • Type: Integer, Float, Text, Array, Boolean etc
  • Standard Library (Amber) + Builtins (with internal automated tests)
  • Written in Rust
  • Editor support with plugin for VS Code, Zed and Vim
  • Amber LSP with TreeSitter available

Tests

Roadmap

  • Dictionary data structure user defined
  • More builtins and stdlib functions: ls
  • More blocks (silent, etc): suppress
  • OOP support, with commands library
  • ShellCheck code 100%
  • Looking for fundings

THE END

- docs.amber-lang.com
- Join our Discord!
- PS: Italian pizza is the best one!