#language #string #programming #programming-language #basic

bin+lib spyglys

A simple programming language for text manipulation

6 releases

0.2.3 Aug 4, 2024
0.2.2 Jul 12, 2024
0.1.1 Jul 9, 2024

#224 in Programming languages

Download history 350/week @ 2024-07-08 21/week @ 2024-07-15 16/week @ 2024-07-22 146/week @ 2024-07-29 22/week @ 2024-08-05 41/week @ 2024-08-12 49/week @ 2024-08-19 9/week @ 2024-08-26

236 downloads per month

Custom license

87KB
2K SLoC

Spyglys

Spyglys is a simple interpreted string manipulation language originally designed for Sakinyje. In general, Spyglys is meant to be embedded in larger programs.

Basic tutorial

General information

Spyglys includes an interactive shell which can be reached through the spyglys shell command. This command takes an extra file argument which can be used to import all of the contents of the file into the scope.

Strings are inside of double quotes ("") Regex patterns are inside of single quotes ('')

In Spyglys, functions are used to handle all string manipulation. In order to maintain simplicity, functions always only have one argument, and one expression to modify that argument. The argument always has the type of regex, though this can be built with expressions inside the definition. The expression that handles the modification always has the type of string. Functions are defined with the def keyword, and the regex pattern they match on is placed between parenthesis.

def trim ('^\s*(?<main>\S(.*\S)?)\s*$'):
    main
end

Functions are called with the syntax you would expect.

> trim("   hi   ")
=> "hi"

Variables can be used to share definitions across multiple functions.

let whitespace = '\s*';
let main = '(?<main>\S(.*\S)?)';

def trim ('^' + whitespace + main + whitespace + '$'):
    main
end

def trim_left ('^' + whitespace + main):
    main
end

def trim_right (main + whitespace + '$'):
    main
end

They can also be strings used inside of the functions

let response = " sounds delicious";
def food_response ('I want some (?<food>.*)'):
    food + response
end

When functions do not match a pattern, they will return EMPTY, which is represented as (). This usually serves as the equivalent of an empty string.

> let response = food_response("I want to eat pasta");
> response
=> ()
> response + " right now."
=> " right now."

Empty function responses can be handled with builtin functions (which use the $function() syntax), which can take multiple parameters. For example, the previous function could be edited to include a default food.

let response = " sounds delicious";
def food_response ('I want some (food|(?<food>.+))'):
    $replace_empty(food, "cake") + response
end
> food_response("I want some pizza")
=> "pizza sounds delicious"
> food_response("I want some food")
=> "cake sounds delicious"

Functions can also be recursive. This function will naively recursively transform xml/html into its equivalent s-expression.

def parse_html ('<(?<tag>\w+)>(?<inner>(?<inner_html><.+)|.+)?</(?<secondtag>\w+)>'):
    "(" + tag + $replace_some(inner, " ") + $replace_some(inner, $if_else(inner_html, parse_html(inner), inner)) + ")"
end

TODO

  • docs
  • more tests
  • new language features

Dependencies

~4–15MB
~177K SLoC