kyleect / locks

A toy language branched from Lox to learn language implementation and tooling. Forked from loxcraft
https://kyleect.github.io/locks/#/docs
MIT License
0 stars 0 forks source link
# 🔓 locks A toy language branched from [Lox](https://www.craftinginterpreters.com/) to learn language implementation. Forked from [loxcraft](https://github.com/ajeetdsouza/loxcraft). [![ci](https://github.com/kyleect/locks/actions/workflows/build-artifacts.yml/badge.svg)](https://github.com/kyleect/locks/actions/workflows/build-artifacts.yml)

Features

Getting Started

Check out the documentation the start running code in the playground.

Example

Playground

fn fizzBuzz(n) {
  for (let i = 1; i <= n; i = i + 1) {
      if (i % 15 == 0) {
        println("FizzBuzz");
      }
      else if (i % 3 == 0) {
        println("Fizz");
      }
      else if (i % 5 == 0) {
        println("Buzz");
      }
      else {
        println(i);
      }
  }
}

fizzBuzz(100);

Usage

Runtime

Download the runtime from the latest build

REPL

$ locks repl

Run files

$ locks run file.locks

Execute locks code as an argument

$ locks exec 'println("Hello");' # Hello

Execute locks code from stdin

$ cat res/benchmarks/fib.locks | locks exec

Print the Abstract Syntax Tree (AST) from Locks code

// example.locks

let value;
println(value); // out: nil
value = 42;
println(value); // out: 42
$ locks parse example.locks
Program {
  stmts: [
    (
      StmtAssign {
        identifier: Identifier {
          name: "value",
          depth: None,
        },
        value: None,
      },
      72..82,
    ),
    (
      StmtPrint {
        value: (
          ExprIdentifier {
            identifier: Identifier {
              name: "value",
              depth: None,
            },
          },
          89..94,
        ),
      },
      83..95,
    ),
    (
      StmtExpr {
        value: (
          ExprAssign {
            identifier: Identifier {
              name: "value",
              depth: None,
            },
            value: (
              Number(
                42.0,
              ),
              116..118,
            ),
          },
          108..118,
        ),
      },
      108..119,
    ),
    (
      StmtPrint {
        value: (
          ExprIdentifier {
            identifier: Identifier {
              name: "value",
              depth: None,
            },
          },
          126..131,
        ),
      },
      120..132,
    ),
  ],
}

Print the disassembled bytecode from Locks code

// ./res/examples/number/fizzbuzz.locks

fn fizzBuzz(n) {
  for (let i = 1; i <= n; i = i + 1) {
      if (i % 15 == 0) {
        println("FizzBuzz");
      }
      else if (i % 3 == 0) {
        println("Fizz");
      }
      else if (i % 5 == 0) {
        println("Buzz");
      }
      else {
        println(i);
      }
  }
}

fizzBuzz(100);
$ locks disassemble ./res/examples/number/fizzbuzz.locks
0000 OP_CLOSURE          0 == '<fn fizzBuzz arity=1>'
| 0000 OP_CONSTANT         0 == '1'
| 0002 OP_GET_LOCAL        2
| 0004 OP_GET_LOCAL        1
| 0006 OP_LESS_EQUAL
| 0007 OP_JUMP_IF_FALSE    7 -> 82
| 0010 OP_POP
| 0011 OP_GET_LOCAL        2
| 0013 OP_CONSTANT         1 == '15'
| 0015 OP_MODULUS
| 0016 OP_CONSTANT         2 == '0'
| 0018 OP_EQUAL
| 0019 OP_JUMP_IF_FALSE   19 -> 29
| 0022 OP_POP
| 0023 OP_CONSTANT         3 == 'FizzBuzz'
| 0025 OP_PRINT
| 0026 OP_JUMP            26 -> 71
| 0029 OP_POP
| 0030 OP_GET_LOCAL        2
| 0032 OP_CONSTANT         4 == '3'
| 0034 OP_MODULUS
| 0035 OP_CONSTANT         2 == '0'
| 0037 OP_EQUAL
| 0038 OP_JUMP_IF_FALSE   38 -> 48
| 0041 OP_POP
| 0042 OP_CONSTANT         5 == 'Fizz'
| 0044 OP_PRINT
| 0045 OP_JUMP            45 -> 71
| 0048 OP_POP
| 0049 OP_GET_LOCAL        2
| 0051 OP_CONSTANT         6 == '5'
| 0053 OP_MODULUS
| 0054 OP_CONSTANT         2 == '0'
| 0056 OP_EQUAL
| 0057 OP_JUMP_IF_FALSE   57 -> 67
| 0060 OP_POP
| 0061 OP_CONSTANT         7 == 'Buzz'
| 0063 OP_PRINT
| 0064 OP_JUMP            64 -> 71
| 0067 OP_POP
| 0068 OP_GET_LOCAL        2
| 0070 OP_PRINT
| 0071 OP_GET_LOCAL        2
| 0073 OP_CONSTANT         0 == '1'
| 0075 OP_ADD
| 0076 OP_SET_LOCAL        2
| 0078 OP_POP
| 0079 OP_LOOP            79 -> 2
| 0082 OP_POP
| 0083 OP_POP
| 0084 OP_NIL
| 0085 OP_RETURN
0002 OP_DEFINE_GLOBAL    1 == 'fizzBuzz'
0004 OP_GET_GLOBAL       1 == 'fizzBuzz'
0006 OP_CONSTANT         2 == '15'
0008 OP_CALL             1
0010 OP_POP
0011 OP_NIL
0012 OP_RETURN

Run the Locks Language Server

$ locks lsp

Docker

VS Code Extension

Download the VS Code extension from the latest build

OR

  1. Run just build-all
  2. Copy ./target/release/locks[.exe] somewhere in your PATH
  3. Install ./vsc/out/locks-language-1.0.0.vsix in VS Code
  4. Create a new file and save as *.locks

Features

Development

Setup

Scripts

Forked

This project was forked from loxcraft. The intent of this fork is to learn about bytecode compilers, stack-based virtual machines, programming language design, and the desire to implement new language features.

There were many potential open source projects that could have been the basis for this toy language but loxcraft had a solid base to start from especially when I was focused on implementing language tooling first. It already had a working language server so the Visual Studio Code extension was a natural place to start.

With the syntax and implementation changes so far the Locks language has divered from Lox and will continue to do so.

Changes Made