Package: scrolls-py
ScrollsScrolls is a small interpreter originally designed to allow users of my discord bots to
make custom commands. It prioritizes control over the interpreter to help prevent abuse,
while still allowing tight integration with python code.LinksDocumentation:https://a-bison.github.io/scrolls-py-docs/Source Code:https://github.com/a-bison/scrolls-pyPyPI:https://pypi.org/project/scrolls-py/Why?The two other candidates for user scripts were python and Lua. Python code is a nightmare
to sandbox properly, and the available Lua interpreters for python didn't give me the kind
of control I wanted over the interpreter. In addition, Lua was a bit much for simple
custom commands. So, I made my own interpreter.There is a scripting language available for Rust calledRhaiwith
a similar concept.Also, I just kinda wanted to try making an interpreted language...GoalsAllow the developer to prevent abuse.Integrate tightly with the parent python application.Keep the syntax as simple as possible.Getting StartedCheck out theLinkssection above.InstallingScrolls may be installed throughpip:Linuxpython3 -m pip install scrolls-pyWindowspy -3 -m pip install scrolls-pyCommand Line UsageThe module comes with a built-in interpreter that may be invoked by executing the
module. (Note that the linux version will be used from now on.)python3 -m scrolls FILETry running some of the examples:python3 -m scrolls ./examples/arithmetic.scrlIf no file is specified, the interpreter will run in interactive mode:python3 -m scrollsExample CodeHere are some sample programs showcasing the basic syntax of Scrolls. See the examples directory for more.Fizzbuzz!def(divisible? a b) {
    return $(eq? 0 $(% $a $b))
}

!for(n in $^(rangev 1 101)) {
    !if($(divisible? $n 15)) {
        print "FizzBuzz"
    } !elif($(divisible? $n 3)) {
        print "Fizz"
    } !elif($(divisible? $n 5)) {
        print "Buzz"
    } !else {
        print $n
    }
}NthFibonacci Numberprint "This will calculate fib N where fib 0 = 0, fib 1 = 1"
print "Enter N."
input n

set output_msg "Fibonacci number" $n "is"

!if($(< $n 2)) {
    print $^output_msg $n
    stop
}

set fib_prev 0
set fib 1
set i 2

!while($(<= $i $n)) {
    set tmp $fib_prev
    set fib_prev $fib
    set fib $(+ $tmp $fib)
    set i $(+ $i 1)
}

print $^output_msg $fibSyntax Quirks# In scrolls everything is a string
"print" "Everything is a string:"
!"for"("operator" "in" "+" "-" "*" "/") {
  "print" $($"operator" "5" "8")
}String Escapesprint "\"test escapes\"\n\ttabbed\n\tlines\nunicode is supported: \u0398hello\u0398\n"Programmatic UsageScrolls may be embedded into any python program:importscrolls# Create an interpreter. Note that an interpreter created this# way will not actually do anything. It's the responsibility of# the user to configure with the desired language features.interpreter=scrolls.Interpreter()# Configure the interpreter with the base language.# scrolls.base_config is provided to make this common task# a bit easier.scrolls.base_config.configure(interpreter)# Configure with stdio commands like input, and printinterpreter.command_handlers.add(scrolls.StdIoCommandHandler())# Run your script.script="""print "Please enter your name:"input name!repeat(4) {print "Hello," $(cat $name "!")}"""interpreter.run(script)Known IssuesInteractive Control CallsMultiple control calls without an explicit command separator will break parsing
in interactive mode. For example, the following wrongly identifieselseas a
command call:>>> !if($false) { print "from if" } !else() { print "from else" }
error:
0 !if($false) { print "from if" } !else() { print "from else" }
                                   ^
line 0: Command_call 'else' not found.A workaround for this is to enter them one line at a time:>>> !if($false) { print "from if" }
>>> !else() { print "from else" }
from elseOr use a semicolon:>>> !if($false) { print "from if" }; !else() { print "from else" }
from elseThis bug does not affect the parsing of whole scripts.Acknowledgementshikari-lightbulbby tandemdude, which inspired the
CallBase extension (seehere).