GraceLanguage
provides a Turning-Complete scripting language can be used in applications such as spreadsheet calculations, database manipulations or game engines.
Grace is a Turning-Complete scripting language written 100% in pure Swift that can be used in applications such as spreadsheet calculations, database manipulations or game engines.
Grace supports features such as global & local variables, enumerations, libraries, functions, and limited structure support (see Grace Variables > Working with Structures documentation). Additionally, Grace was designed to be easily extended by Registering external functions. This allow Grace to be fully interoperable with its host language and program.
Grace was named in honor of Rear Admiral Grace M. Hopper. Not only did she come up with the idea of high-level computer programming languages, but we also have her to thank for the term "debugging".
From Wikipedia:
One of the first programmers of the Harvard Mark I computer, she was a pioneer of computer programming. Hopper was the first to devise the theory of machine-independent programming languages, and the FLOW-MATIC programming language she created using this theory was later extended to create COBOL, an early high-level programming language still in use today.
If you find GraceLanguage
useful and would like to help support its continued development and maintenance, please consider making a small donation, especially if you are using it in a commercial product:
It's through the support of contributors like yourself, I can continue to build, release and maintain high-quality, well documented Swift Packages like GraceLanguage
for free.
Swift Package Manager (Xcode 11 and above)
- In Xcode, select the File > Add Package Dependency… menu item.
- Paste
https://github.com/Appracatappra/GraceLanguage.git
in the dialog box. - Follow the Xcode's instruction to complete the installation.
Why not CocoaPods, or Carthage, or etc?
Supporting multiple dependency managers makes maintaining a library exponentially more complicated and time consuming.
Since, the Swift Package Manager is integrated with Xcode 11 (and greater), it's the easiest choice to support going further.
In Grace Enumerations, Structures and Functions are defined in the Global Space along with a special function main
that acts as the main entry point into the program.
Additionally, library Imports and Variables can be defined in the Global Space and they will be available in everywhere throughout the Grace program. The StandardLib contains built-in functions such as print
and printf
. StringLib contains string manipulation functions such as leftString
and midString
.
Let's take a look at a simple Grace program to see how this works:
import StandardLib;
enumeration Colors {
red,
orange,
yellow,
green,
blue,
indigo,
violet
}
structure FullName {
first:string,
last:string
}
main {
var n:int;
var words:string array = ["One", "Two", "Three", "Four"];
var color:enumeration Colors = #Color~green;
var person:structure FullName = new FullName(first:"Jane", last:"Doe");
var name:string = @join($person~first, "!");
let $n = (@count($words) - 1);
if ($words[$n] = "Four") {
call @print("It is four.");
} else {
call @print("It is not four.");
}
iterate word in $words {
call @print($word);
}
call @sayHello($name);
}
function join(a:string, b:string) returns string {
return ($a + $b);
}
function sayHello($name:string) {
call @printf("Hello {0}", [$name]);
}
So a few things to point out here:
var
is used to define a variable.let
is used to modify a variable.- All instructions end with a semicolon
;
. @
is used to dereference a function (either internal or external).$
is used to dereference a variable.#
is used to dereference anenumeration
.~
is used to dereference a property of anenumeration
orstructure
.- The functions
@print
,@printf
and@count
are defined in theStandardLib
imported at the start of the program.
When designing the Grace Language, one of my driving factors was to keep the language small, light and fast. To achieve this goal, I chose to use decorators when dereferencing Functions, Variables and Enumerations.
This allowed me to keep the GraceCompiler
quick and small, since the decorator tells compiler exactly what it is processing, while not putting to much effort on the developer and not cluttering the language too much.
This is also why you use the let
and call
keywords for modifying variables and calling functions and why expressions always follow the form (value operator value)
.
These concessions keep the GraceCompiler
from having to determine the developer's intent, thus speeding up the compile process.
The GraceLanguage Package has the tools to compile and run programs written in Grace.
The GraceCompiler
converts a string
or text file containing the Grace Program into byte code for faster execution.
You can either precompile your Grace Program using the GraceCompiler
or you can call methods of the GraceRuntime
to compile and execute a Grace Program in one step.
Additionally, you can either create your own instance of the GraceCompiler
or use the common shared instance GraceCompiler.shared
.
The following is an example of precompiling a Grace Program:
import GraceLanguage;
var program:String {
return """
main {
call @print("Hello World!");
}
"""
}
do {
let executable = try GraceCompiler.shared.compile(program: program)
} catch {
print("Error: \(error)")
}
For more information, please see the included documentation.
The GraceRuntime
can either execute a precompiled Grace Program or it can compile and execute the program in one step.
The following is an example of compiling and executing a program in one step:
import GraceLanguage;
var program:String {
return """
main {
call @print("Hello World!");
}
"""
}
do {
try GraceRuntime.shared.run(program: program)
} catch {
print("Error: \(error)")
}
Additionally, you can run a snippet of Grace Code without the required main function
using:
do {
try GraceRuntime.shared.run(script: "call @print('Hello World!');")
} catch {
print("Error: \(error)")
}
Using this function, the snippet of code will be wrapped in the following Grace code before compiling and executing:
import StandardLib;
import StringLib;
import MacroLib;
main{
// Your code goes here...
}
All of the execution methods built into the GraceCompiler
can return a result to the calling program. For example:
let code = """
import StandardLib;
main {
var n:int = 5;
var x:int = 5;
return ($n + $x);
}
"""
let result = try GraceRuntime.shared.run(program: code)
print("The result is: \(result?.int)")
Upon executing the above code result
will be a GraceVariable
containing 10
.
The GraceRuntime.expandMacros
function can expand Grace Function Macros inside of a given string by executing the named function and inserting the result in the string. For example:
let text = GraceRuntime.shared.expandMacros(in: "The answer is: @intMath(40,'+',2)")
After running the above code, the value of text
will be The answer is: 42
.
For more information, please see the included documentation.
The Package includes full DocC Documentation for all features.