diff --git a/README.md b/README.md index d560a71..c4ec1b6 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,29 @@ This repository holds the reference implementation for Toy version 2.x, written # Syntax -Watch this space. +```toy +fn makeCounter() { + var counter: Int = 0; -(The `scripts` or `tests` directory might help, the docs website is WIP.) + fn increment() { + return ++counter; + } + + return increment; +} + +var tally = makeCounter(); + +while (true) { + var result = tally(); + + print result; //prints 1 to 10 + + if (result >= 10) { + break; + } +} +``` # Building @@ -30,15 +50,9 @@ This project requires `gcc` and `make` by default, but should also work in other Run `make` in the root directory to build the shared library named `libToy.so` and a useable REPL named `repl.out`. -# Tools - -Watch this space. - -(There's some utility functions in `repl/` that are WIP but useful.) - # Documentation -Watch this space. +The contents of `docs/` is also available on the official website [toylang.com](https://toylang.com/). # License diff --git a/docs/src/404.md b/docs/src/404.md index edca637..8b2ae4b 100644 --- a/docs/src/404.md +++ b/docs/src/404.md @@ -1 +1,3 @@ +# 404 + Nobody here but us chickens! \ No newline at end of file diff --git a/docs/src/README.md b/docs/src/README.md index f4944a3..1ea446b 100644 --- a/docs/src/README.md +++ b/docs/src/README.md @@ -4,7 +4,7 @@ The Toy Programming Language is an imperative, bytecode-interpreted, embeddable scripting language. Rather than functioning independently, it serves as part of another program, the "host". This design allows for straightforward customization by both the host's developers and end users, achieved by exposing program logic through external scripts. -# Nifty Features +## Nifty Features * Simple C-like syntax * Intermediate AST and bytecode representations @@ -14,8 +14,34 @@ The Toy Programming Language is an imperative, bytecode-interpreted, embeddable * Can re-direct output, error and assertion messages * Open-Source under the zlib license -# Further Reading +## Syntax -This website is under construction - for further info, see the official repository: [https://gitea.krgamestudios.com/krgamestudios/Toy](https://gitea.krgamestudios.com/krgamestudios/Toy), or the GitHub mirror: [https://github.com/krgamestudios/Toy](https://github.com/krgamestudios/Toy). +```toy +fn makeCounter() { + var counter: Int = 0; -An example of Toy in action: [Vampire Toyvivors](https://gitea.krgamestudios.com/krgamestudios/VampireToyvivors). \ No newline at end of file + fn increment() { + return ++counter; + } + + return increment; +} + +var tally = makeCounter(); + +while (true) { + var result = tally(); + + print result; //prints 1 to 10 + + if (result >= 10) { + break; + } +} +``` + +## Further Reading + +This website is a work in progress - for further info, see the official repository: [https://gitea.krgamestudios.com/krgamestudios/Toy](https://gitea.krgamestudios.com/krgamestudios/Toy), or the GitHub mirror: [https://github.com/krgamestudios/Toy](https://github.com/krgamestudios/Toy). + +An example of Toy in action: [Vampire Toyvivors](https://gitea.krgamestudios.com/krgamestudios/VampireToyvivors) (a simple "game" used for testing). \ No newline at end of file diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index cff3a64..26ef520 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -1,4 +1,5 @@ # Summary -- [Introduction](./README.md) -- [Quick Start](./quickstart.md) \ No newline at end of file +- [Front Page](./README.md) +- [Quick Start](./quickstart.md) +- [Cheat Sheet](./cheatsheet.md) \ No newline at end of file diff --git a/docs/src/cheatsheet.md b/docs/src/cheatsheet.md new file mode 100644 index 0000000..a9a7045 --- /dev/null +++ b/docs/src/cheatsheet.md @@ -0,0 +1,144 @@ +# Cheat Sheet + +## Compile and Run A Snippet Of Code + +```c +#include "toy_lexer.h" +#include "toy_parser.h" +#include "toy_compiler.h" +#include "toy_vm.h" +#include + +int main() { + //example code + const char* source = "print \"Hello world!\";"; + + //buckets use the arena pattern for memory allocation + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + + //compile the code + Toy_Lexer lexer; + Toy_bindLexer(&lexer, (char*)source); + + Toy_Parser parser; + Toy_bindParser(&parser, &lexer); + + Toy_Ast* ast = Toy_scanParser(&bucket, &parser); + unsigned char* bytecode = Toy_compileToBytecode(ast); + + //the ast, which is stored in this bucket, is no longer needed + Toy_freeBucket(&bucket); + + //the virtual machine used at runtime + Toy_VM vm; + Toy_initVM(&vm); + Toy_bindVM(&vm, bytecode, NULL); + + //execute the given code + Toy_runVM(&vm); + + //cleanup after ourselves + Toy_freeVM(&vm); + free(bytecode); +} +``` + +## Quick and Dirty Compilation + +```c +unsigned char* compileSource(const char* source) { + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + + Toy_Lexer lexer; + Toy_bindLexer(&lexer, source); + + Toy_Parser parser; + Toy_bindParser(&parser, &lexer); + + Toy_Ast* ast = Toy_scanParser(&bucket, &parser); + unsigned char* bytecode = Toy_compileToBytecode(ast); + + Toy_freeBucket(&bucket); + return bytecode; +} +``` + +## API Functions + +This is a rough outline of all API functions declared in Toy's headers. As a rule, functions that begin with `TOY_API` are useable and begin with `Toy_`, while functions that begin with `Toy_private_` are generally not intended for use, and only exposed for technical reasons. + +*Note: This list is updated manually, if something is outdated let me know.* + +```c +TOY_API Toy_Array* Toy_resizeArray(Toy_Array* array, unsigned int capacity); +TOY_API void Toy_setOpaqueAttributeHandler(Toy_OpaqueAttributeHandler cb); +TOY_API void Toy_collectBucketGarbage(Toy_Bucket** bucketHandle) { +TOY_API Toy_Bucket* Toy_allocateBucket(unsigned int capacity); +TOY_API unsigned char* Toy_partitionBucket(Toy_Bucket** bucketHandle, unsigned int amount); +TOY_API void Toy_releaseBucketPartition(unsigned char* ptr); +TOY_API void Toy_freeBucket(Toy_Bucket** bucketHandle); +TOY_API void Toy_collectBucketGarbage(Toy_Bucket** bucketHandle); +TOY_API unsigned char* Toy_compileToBytecode(Toy_Ast* ast); +TOY_API void Toy_freeFunction(Toy_Function* fn) { +TOY_API Toy_Function* Toy_createFunctionFromBytecode(Toy_Bucket** bucketHandle, unsigned char* bytecode, Toy_Scope* parentScope); +TOY_API Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nativeCallback callback); +TOY_API Toy_Function* Toy_copyFunction(Toy_Bucket** bucketHandle, Toy_Function* fn); +TOY_API void Toy_freeFunction(Toy_Function* fn); +TOY_API void Toy_bindLexer(Toy_Lexer* lexer, const char* source); +TOY_API void Toy_bindParser(Toy_Parser* parser, Toy_Lexer* lexer); +TOY_API Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser); +TOY_API void Toy_resetParser(Toy_Parser* parser); +TOY_API void Toy_print(const char* msg); +TOY_API void Toy_error(const char* msg); +TOY_API void Toy_assertFailure(const char* msg); +TOY_API void Toy_setPrintCallback(Toy_callbackType cb); +TOY_API void Toy_setErrorCallback(Toy_callbackType cb); +TOY_API void Toy_setAssertFailureCallback(Toy_callbackType cb); +TOY_API void Toy_resetPrintCallback(void); +TOY_API void Toy_resetErrorCallback(void); +TOY_API void Toy_resetAssertFailureCallback(void); +TOY_API Toy_Scope* Toy_pushScope(Toy_Bucket** bucketHandle, Toy_Scope* scope); +TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope); +TOY_API void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_ValueType type, Toy_Value value, bool constant); +TOY_API void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value); +TOY_API Toy_Value* Toy_accessScopeAsPointer(Toy_Scope* scope, Toy_String* key); +TOY_API bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key); +TOY_API Toy_Stack* Toy_allocateStack(void); +TOY_API void Toy_freeStack(Toy_Stack* stack); +TOY_API void Toy_resetStack(Toy_Stack** stackHandle); +TOY_API void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value); +TOY_API Toy_Value Toy_peekStack(Toy_Stack** stackHandle); +TOY_API Toy_Value Toy_popStack(Toy_Stack** stackHandle); +TOY_API Toy_String* Toy_toString(Toy_Bucket** bucketHandle, const char* cstring); +TOY_API Toy_String* Toy_toStringLength(Toy_Bucket** bucketHandle, const char* cstring, unsigned int length); +TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, unsigned int length); +TOY_API Toy_String* Toy_copyString(Toy_String* str); +TOY_API Toy_String* Toy_concatStrings(Toy_Bucket** bucketHandle, Toy_String* left, Toy_String* right); +TOY_API void Toy_freeString(Toy_String* str); +TOY_API unsigned int Toy_getStringLength(Toy_String* str); +TOY_API unsigned int Toy_getStringRefCount(Toy_String* str); +TOY_API char* Toy_getStringRaw(Toy_String* str); +TOY_API int Toy_compareStrings(Toy_String* left, Toy_String* right); +TOY_API unsigned int Toy_hashString(Toy_String* string); +TOY_API Toy_Table* Toy_allocateTable(unsigned int minCapacity); +TOY_API void Toy_freeTable(Toy_Table* table); +TOY_API void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value); +TOY_API Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key); +TOY_API void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key); +TOY_API Toy_Value Toy_unwrapValue(Toy_Value value); +TOY_API unsigned int Toy_hashValue(Toy_Value value); +TOY_API Toy_Value Toy_copyValue(struct Toy_Bucket** bucketHandle, Toy_Value value); +TOY_API void Toy_freeValue(Toy_Value value); +TOY_API bool Toy_checkValueIsTruthy(Toy_Value value); +TOY_API bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right); +TOY_API bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right); +TOY_API int Toy_compareValues(Toy_Value left, Toy_Value right); +TOY_API union Toy_String_t* Toy_stringifyValue(struct Toy_Bucket** bucketHandle, Toy_Value value); +TOY_API const char* Toy_getValueTypeAsCString(Toy_ValueType type); +TOY_API void Toy_resetVM(Toy_VM* vm, bool preserveScope, bool preserveStack); +TOY_API void Toy_initVM(Toy_VM* vm); +TOY_API void Toy_inheritVM(Toy_VM* parentVM, Toy_VM* subVM); +TOY_API unsigned int Toy_runVM(Toy_VM* vm); +TOY_API void Toy_freeVM(Toy_VM* vm); +TOY_API Toy_Value Toy_getReturnValueFromVM(Toy_VM* parentVM, Toy_VM* subVM); +``` \ No newline at end of file diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 20f229b..6f2b8ca 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -4,7 +4,7 @@ To help you start using Toy as fast as possible, here are the most useful elemen ## Keyword 'print' -The `print` keyword takes one value as a parameter, which is sent to stdout by default, or can be redirected elsewhere using C. +The `print` keyword prints a given value to stdout (or elsewhere if configured with the API). ``` print "Hello World!"; @@ -12,7 +12,7 @@ print "Hello World!"; ## Keyword 'assert' -The `assert` keyword takes two values as parameters, separated by a comma. If the first value is falsy or `null`, the optional second parameter is sent to stderr by default, or can be redirected elsewhere using C. If no second parameter is provided, a generic error message is used instead. +The `assert` keyword takes two values separated by a comma. If the first value is falsy or `null` the optional second parameter is printed to stderr (or elsewhere if configured with the API). If no second parameter is provided a generic error message is used instead. ``` //nothing happens @@ -24,7 +24,7 @@ assert null, "Hello world!"; ## Variables and Types -Variables can be declared with the `var` keyword, and can be given an optional type from the list below. If no type is specified, `Any` is used by default. +Variables are declared with the `var` keyword with and an optional type from the list below. If no type is specified `Any` is used instead. ``` var answer = 42; @@ -32,31 +32,29 @@ var answer = 42; var question: String = "How many roads must a man walk down?"; ``` -To make a variable immutable, use the `const` keyword after the type declaration. In this case, it must be assigend a value. +To make a variable immutable put the `const` keyword after the type. If you do, it must be assigned a value. ``` -var quote: string const = "War. War never changes."; +var quote: String const = "War. War never changes."; ``` -The types available in Toy are: +Toy's types are: | type | name | description | | --- | --- | --- | | `Bool` | Boolean | Either `true` or `false`. | -| `Int` | Integer | Any whole number (32-bits). | -| `Float` | Float | A decimal number (32-bits), using floating-point arithmetic. | -| `String` | String | A series of characters used for text processing. | +| `Int` | Integer | Any signed whole number (32-bits). | +| `Float` | Float | Any signed decimal number (32-bits), using floating point arithmatic. | +| `String` | String | Normal text, effectively utf-8. | | `Array` | Array | A series of values stored sequentially in memory. | -| `Table` | Table | A series key-value pairs stored in such a way that allows for fast lookups. Booleans, functions, opaques and `null` can't be used as keys. | -| `Function` | Function | A chunk of reusable code that takes zero or more parameters, and may return a result. Functions are declared with the `fn` keyword. | -| `Opaque` | Opaque | This value is unusable in Toy, but allows you to pass data between C bindings. | -| `Any` | Any | The default type when nothing is specified. Theis can hold any value. | +| `Table` | Table | A series key-value pairs stored in a hash table. Booleans, functions, opaques and `null` can't be used as keys. | +| `Function` | Function | A chunk of reusable code that takes zero or more parameters, and may return a result. Functions are declared with the `fn` keyword, or in the API. | +| `Opaque` | Opaque | This value is unusable in Toy, but allows you to pass data between C bindings provided with the API. | +| `Any` | Any | The default type when nothing is specified. It can hold any value. | ## Control Flow -Making a decision, or repeating a chunk of code multiple times, is essential for any general purpose language. - -Choosing between two options can be done with the `if-then-else` else statement. If the condition is truthy, the 'then-branch' will be executed. Otherwise, the optional 'else-branch' is executed instead. +Making a decision, or repeating a chunk of code multiple times, is essential for any language. Choosing between multiple options can be done with the `if-then-else` statement - if the condition is truthy, the 'then-branch' will be executed. Otherwise, the optional 'else-branch' is executed instead. ``` var answer = 42; @@ -79,7 +77,7 @@ if (challenge == "hard") { //the else-branch is optional ``` -To repeat a certain action, use the `while-then` loop, which repeats the body as long as the condition is true at the beginning of each loop. +To repeat a certain action, use the `while-then` loop, which repeats the body as long as the given condition remains true on each loop. ``` var loops = 0; @@ -103,7 +101,7 @@ while (true) { } ``` -*Note: The `for` loop is coming, eventually, but isn't vital right now.* +*Note: The `for` loop is coming soon, and will allow for iteration over an array or table, but isn't vital right now.* ## Arrays and Tables @@ -132,13 +130,13 @@ var table = ["alpha": 1, "beta": 2, "gamma": 3]; //the 'Table' keyword can define the type, and an empty table still has a colon var under: Table = [:]; -//printing a table does NOT guarantee internal order, but the elements can be accessed with the keys. +//printing the whole table does NOT guarantee internal order print table["beta"]; ``` ## Attributes -Some value types, including Strings, Arrays and Tables, have "attributes" which are accessible with the dot `.` operator. These can expose internal values or components for manipulating said values. +Some values, including Strings, Arrays and Tables, have "attributes" which are accessible with the dot `.` operator. These can expose internal values or components for manipulating said values. ``` var string = "Hello World"; @@ -159,12 +157,13 @@ table.remove("alpha"); //table = ["beta":2,"key":4] var emptyTable = [:]; ``` +Opaques can also be given attributes, but this requires some in-depth understanding of the API, so won't be covered here. ## Functions -Functions are defined with the `fn` keyword, and follow a c-like syntax, with optional types on the parameters: +Functions are defined with the `fn` keyword, and follow a c-like syntax, with optional types on each parameter: -``` +```toy fn fib(n: Int) { if (n < 2) return n; return fib(n-1) + fib(n-2); @@ -173,7 +172,15 @@ fn fib(n: Int) { print fib(12); //144 ``` -## External Libraries and Extending Toy +```toy +fn isLeapYear(n: Int) { + if (n % 400 == 0) return true; + if (n % 100 == 0) return false; + return n % 4 == 0; +} +``` -Watch this space, docs for the C API are coming soon. +## External API and Extending Toy + +*Note: Watch this space, docs for the C API are coming soon. For now, the [Cheat Sheet](/cheatsheet) can get you started.* diff --git a/scripts/hello_world.toy b/scripts/hello_world.toy index f02feed..71aa9e7 100644 --- a/scripts/hello_world.toy +++ b/scripts/hello_world.toy @@ -1,11 +1,12 @@ -var array = [1,2,3]; -print array; - -fn double(x: Int) { return x * 2; } - -array.forEach(double); - -print array; \ No newline at end of file +if (true) { + print "Who?"; +} +else if (true) { + print "What?"; +} +else { + print "IDK"; +} \ No newline at end of file diff --git a/source/toy_bucket.h b/source/toy_bucket.h index 3361b3d..00014e2 100644 --- a/source/toy_bucket.h +++ b/source/toy_bucket.h @@ -57,3 +57,4 @@ TOY_API void Toy_collectBucketGarbage(Toy_Bucket** bucketHandle); #define TOY_BUCKET_IDEAL (TOY_BUCKET_64KB - sizeof(Toy_Bucket)) #endif +//TODO: check for leaks when freeBucket is called, for debugging \ No newline at end of file