Skip to content

mkhan45/slang-v2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

slang

Slang is a treewalk scripting language interpreter from loosely following https://craftinginterpreters.com/. I've also used https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html to write the parser.

Since this is a treewalk interpreter and I'm planning on writing a bytecode interpreter version, I put absolutely no effort into optimization and it's quite slow. The project euler tests are translated from https://github.com/asterane/project-euler since Slang is basically C with less features. Throughout the Readme, Rust syntax highlighting is used because it's close enough.

In the REPL, add '~' at the end of the input. This is the easiest way I could think of to make it work with multiline.

There's also a proof of concept bytecode compiler on the bytecode branch which compiles instructions for TinyVM. It supports only integers, if statements, and loops, but is many times faster than the treewalk version. I plan to design and write a more complete bytecode interpreter sometime soon.

Examples

Project Euler 01

Prints the sum of all numbers under 1000 that are divisible by 3 or 5.

let sum = 0

for (let i = 0; i < 1000; i += 1) {
    if ((i % 3 == 0) || (i % 5 == 0)) {
        print(i)
        sum += i
    }
}

sum

Recursive Fibonacci

fn fib(n) {
    if (n < 2) {
        1
    } else {
        fib(n - 1) + fib(n - 2)
    }
}

fib(15)

Memoized Fibonacci

let arr = [1, 1]

let n = 40

for (let i = 2; i < n; i += 1) {
    push(arr, arr[i - 1] + arr[i - 2])
}

for (let i = 0; i < len(arr); i += 1) {
     print(arr[i])
}

Features

Variables

  • Ints
  • Floats
  • Strings
  • Arrays
  • Booleans

To declare a variable, use let. To change the variable with typechecking, just assign it with =.

let x = 5
let y = "abc"

x = "abc" # errors
let y = 5 # doesn't error

Arithmetic operations are implemented between Floats and Integers.

Loops

While loops and C-style for loops are implemented.

let x = 0
while (x < 10) {
    print(x)
    x += 1
}

for (let i = 0; i < 10; i += 1) {
    print(x)
}

for loops are limited to one statement or expression per section.

Scopes

Any section delimited by curly braces is a scope. Variables in outer scopes are accessible and variables go out of scope at the end of the block they are declared in.

let x = 5

{
    print(x) # 5
    let x = "abc"
    print(x) # "abc"
}

print(x) # 5

Arrays

Arrays are expandible, heterogenous, and nestable. They can be indexed by square brackets. They also use two built in functions, push, and len.

let a = [1, 2, 3, "abc"]
print(a[0]) # 1
print(a[0 + 1]) # 2 
print(a[2 - a[0] + 1]) # 3

push(a, 5)
push(a, a)
print(a) # debug output, not very pretty
print(a[len(a) - 1][0]) # 1

Functions

First class functions are declared using the fn keyword.

fn add(a, b) {
    a + b
}

fn run(f, a, b) {
    f(a, b)
}

fn square(a) {
    a * a
}

fn call_n_times(n, f, x) {
    if (n == 1) {
        f(x)
    } else {
        call_n_times(n - 1, f, f(x))
    }
}

print(run(add, 15, 20)) # 35
print(call_n_times(4, square, 2)) # 65536

Examples

There are more examples in the test_files directory. The most impressive one is pong_stdg.slang which is Pong with two AIs. It needs to be run with https://github.com/calebwin/stdg/releases/tag/v0.2.0.

Releases

No releases published

Packages

No packages published