{"id":13610484,"url":"https://github.com/brwhale/KataScript","last_synced_at":"2025-04-12T22:34:04.453Z","repository":{"id":50617077,"uuid":"316845158","full_name":"brwhale/KataScript","owner":"brwhale","description":"A simple scripting language","archived":false,"fork":false,"pushed_at":"2023-12-26T06:17:07.000Z","size":4097,"stargazers_count":96,"open_issues_count":6,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-08-01T19:55:15.205Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brwhale.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-11-29T00:08:18.000Z","updated_at":"2024-04-29T05:44:39.000Z","dependencies_parsed_at":"2023-12-14T03:24:02.645Z","dependency_job_id":"213de2c2-e2fd-4e55-82c1-f1c9e5608191","html_url":"https://github.com/brwhale/KataScript","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brwhale%2FKataScript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brwhale%2FKataScript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brwhale%2FKataScript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brwhale%2FKataScript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brwhale","download_url":"https://codeload.github.com/brwhale/KataScript/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223549288,"owners_count":17163631,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T19:01:45.116Z","updated_at":"2024-11-07T16:31:20.958Z","avatar_url":"https://github.com/brwhale.png","language":"C++","readme":"# KataScript\nKataScript is a simple scripting language with familiar syntax, designed to be easily embedded in C++ applications.\n\n[In-Browser Demo](https://brwhale.github.io/KataScript/)\n\n## Index\n- [Overview](#overview)\n  - [Purpose](#purpose)\n  - [Values and Types](#values-and-types)\n  - [Type Coercion](#typecoercion)\n  - [Variables](#variables)\n  - [Memory](#memory)\n  - [Special Characters](#special-characters)\n  - [Keywords](#keywords)\n  - [Comments](#comments)\n  - [Importing Code](#importing-code)\n- [Control Flow](#control-flow)\n  - [Functions](#functions)\n  - [Loops](#loops)\n  - [if/else](#ifelse)\n- [Collections](#collections)\n  - [Arrays](#arrays)\n  - [Lists](#lists)\n  - [Dictionaries](#dictionaries)\n  - [Vec3](#vec3)\n- [Classes](#classes)\n  - [Inheritance](#inheritance)\n- [Errors](#errors)\n- [Built-in Functions](#built-in-functions)\n  - [Math Operators](#math-operators)\n  - [Comparison Operators](#comparison-operators)\n  - [Alias Functions](#alias-functions)\n  - [Other Functions](#other-functions)\n  - [Precedence](#precedence)\n- [Examples](#examples)\n  - [Hello World](#hello-world)\n  - [Fizzbuzz](#fizzbuzz)\n  - [Fizzbuzz With Map](#fizzbuzz-with-map)\n  - [Fibonacci Series](#the-fibonacci-series)\n  - [Functional Programming](#functional-programming)\n- [C++ Integration](#c-integration)\n  - [Invoke C++ From KataScript](#invoke-c-from-katascript)\n  - [Invoke KataScript From C++](#invoke-katascript-from-c)\n  - [C++ Types and Methods](#c-types-and-methods)\n  - [C++ Usage Pattern](#c-usage-pattern)\n- [Future Features Roadmap](#future-features-roadmap)\n\n## Overview\n\n### Purpose\nKataScript is designed to be lightweight, secure, sane, and easy to use. I made KataScript because I wanted scripting for my game engine but I did not enjoy the quirks of Lua or the security issues of including a Python or JavaScript environment. Therefore the goal of KataScript is to provide the sanest possible embedded scripting with the least amount of hurdles.\n\n### Values and Types\nLike most scripting languages, KataScript is dynamically typed. \n\nValues can currently have 11 different types: `null`, `int`, `float`, `vec3`, `function`, `userpointer`, `string`, `array`, `list`, `dictionary`, and `class`. \n\n`null`: the default type of any values. Converts to 0\n\n`int`: 32/64 bit signed integers supplied by underlying C++ int type. Boolean logic uses the int type like C, 0 = False, anything else = True. Number types are 64 bits by default, but you can define `KATASCRIPT_USE_32_BIT_NUMBERS` to use 32 bit numbers.\n\n`float`: 32/64 bit signed floating point IEEE-754 supplied by underlying C++ float type.\n\n`vec3`: 3 32 bit floats wraped into a struct. Used for 3d vectors, math, etc. Directly casts to glm::vec3\n\n`function`: A function reference, can be assigned, called, and passed around but not compared or converted.\n\n`userpointer`: A void* pointer. Similar to a function, a userpointer can be passed around or stored in collections, but not compared or converted.\n\n`string`: A mutable UTF8 character string supplied by underlying C++ std::string type. (some unicode doesn't work in the demo though because of the JavaScript interface)\n\n`array`: A collection of other values. An array must be homogeneous (all values of the same type) and cannot contain other collections, supplied by underlying C++ std::vector containing values contiguously and represented in the unboxed base type. Array data is acessed by integer index starting from 0.\n\n`list`: A collection of other values. A list can be heterogeneous and contain any type, supplied by underlying C++ std::vector containing references to values. List data is acessed by integer index starting from 0. Slower than an `array` but more flexible.\n\n`dictionary`: A collection of other values, but this time as a hashmap. A dictionary can contain any type like a list, but it can be indexed with any non-collection type. Supplied by underlying C++ std::unordered_map type.\n\n`class`: A class type. Contains member variables and functions. Class functions are implicitly called from \"class scope\" so that means that to each of the class's functions, the class's variables are local. (aka normal class-function scoping compared to other languages)\n\n### Type Coercion\nThere is minimal type coercion in KataScipt. Int will be promoted to Float for any operation between the two types, and String will be promoted to a List of characters when operating with a List. Attempting to compare a number type to a string or a list (unless it's only 1 element long and that element is a number) will throw an error. If you want to purposely convert values, there are built in casting/parsing functions `bool()`, `int()`, `float()`, `string()`, `array()`, `list()`.\n\n### Variables\nSimply attempt to use a variable and it will be created in the current scope.\n\n```c#\ni = 5;\n```\n\nThe variable `i` now stores the integer `5`.\n\nIf you want to store a float or a string in `i`, you can do that too.\n\n```c#\ni = 5.0; // i is a float\ni = \"string value\"; // i is now a string\n```\n\nIf you run into scoping issues, you can also use the `var` keyword to ensure a new variable is created. Variables created inside functions should use the var keyword to avoid issues when using higher order functions.\n\n```c#\nvar i = 3;\n```\n\n### Memory\nKataScript is not technically garbage collected but does offer automatic memory management. It uses reference counting and scoping to free memory immediately after a value isn't being used anymore.\n\n### Special Characters\n`\"`, `,`, `.`, `=`, `!`, `\u0026`, `|`, `+`, `-`, `%`, `*`, `/`, `\\`, `\u003c`, `\u003e`, `(`, `)`, `[`, `]`, `{`, `}`, and `;` are characters with special meaning to the parser and thus cannot be used in identifiers.\n\nWhitespace outside of strings is stripped before parsing. \nQuotation marks inside a string must be escaped like `\\\"`\n\n### Keywords\n`if`, `else`, `func`, `var`, `return`, `foreach`, `for`, and `while` are reserved for control flow constructs and cannot be used as an identifier.\n\n`true`, `false`, and `null` are reserved for constants and cannot be used as an identifier.\n\n`import` is reserved for importing files and modules.\n\n### Comments\nComments are anything in a line after `//` that isn't in a string literal and will be ignored.\n```c#\n// this is a comment\n```\nComments need not start at the beginnning of a line.\n\n### Importing Code\nThe `import` keyword is used to import one script into another, allowing you to reduce boilerplate and reuse code easier.\n```c#\nimport \"demo.ks\"\n```\n\n## Control Flow\n\n### Functions\nFunctions are called with the syntax `name(arg(s)...)`. For example:\n\n```c#\nprint(100);\nprint(\"hello \", \"world\");\n```\n\nFunctions can also be called using dot syntax:\n\n```c#\n// these are the same\nlength([1,2,3,4]);\n[1,2,3,4].length();\n\n// these too\nrange([1,2,3,4],2,3);\n[1,2,3,4].range(2,3);\n```\n\nFunctions are created using the `func` keyword. Functions may return values, but it is not strictly required.\n\n```c#\nfunc add1(a) {\n  return a + 1;\n}\n```\n\n### Loops\n`while()` and `for()` are synonyms that mean start a loop. Either way you can put 1-3 expressions seperated by semicolons inside the parens.\n- 1 expression: behaves like a standard while loop\n- 2 expressions: behaves like a for loop with no initialization statment\n- 3 expressions: behaves like a standard for loop\n\n`foreach(item; collection)` will loop over each item in a list or array with `item` referencing each item \n\nThen just put the loop contents inside of curly brackets:\n\n```c#\ni = 20;\nwhile (i \u003e 0) {\n  print(--i);\n}\n```\n\n```c#\nfor (i = 0; i \u003c 100; i++) {\n  print(i);\n}\n```\n\n```c#\nforeach (i; [1,2,3] + [4,5]) { print(i); }\nforeach (i; array(1,2,3,4,5)) { print(i); }\nforeach (i; someListVariable) { print(i); }\n```\n\n### if/else\n`if`/`else if`/`else` all work how you'd expect.\n\n```c#\nif (5 == 5) { \n  print(\"pie\"); \n} else if (5 == 6) { \n  print(\"cake\"); \n} else { \n  print(\"coffee\"); \n}\n```\n\n## Collections\nA collection literal looks like `[value(s)...]` and a collection access looks like `name[index]` (note that collections are 0-indexed). A collection literal will resolve to an `array` if all the types are the same and a `list` otherwise.\nThe `length()` function can tell you the size of a collection.\n\n### Arrays\nAn array is a collection of unboxed values. All values in an array must be the same type and that type cannot be a collection.\n\n```c#\ni = [1, 2, 3]; // array from literal\ni = array(1, \"fish\", 2, 3); // array function\n// array type is the type of the first element added.\nprint(i[1]);\n// prints: 2, note how \"fish\" was not added to the array\nprint(length(i));\n// prints: 3, again only the integer values were accepted\n```\n\n### Lists\nA list is a collection of boxed value references. A list can store values of any type and can store other collections.\n\n```c#\ni = [1.0, 2, 3, \"squid\"]; // list from literal\ni = list(1, 2, 3); // list function\nprint(i[1]);\n// prints: 2\nprint(length(i));\n// prints: 3\nj = list(4, 5, 6);\nk = list(7, 8, 9);\na = list(i, j, k);\nprint(a);\n// prints: 1, 2, 3, 4, 5, 6, 7, 8, 9\ni = list(\"fish\", \"tacos\");\nprint(a);\n// prints: fish, tacos, 4, 5, 6, 7, 8, 9\nk = list(7, \"string\", 9.0);\nprint(a);\n// prints: fish, tacos, 4, 5, 6, 7, string, 9.000000\n```\n\nNote how list elements follow reference semantics, if you wish to actually copy the data into a list, you can use the copy function to create a copy like so:\n\n```c#\ni = list(1,2,3);\na = copy(i);\ni = list(5,6,7);\nprint(a);\n// prints: 1, 2, 3\n```\n\n### Dictionaries\nA dictionary is a collection that can be indexed by any non-collection type\n\n```c#\ni = dictionary();\ni[\"squid\"] = 10;\ni[\"octopus\"] = 8;\ni[69] = \"nice\";\ni[i[69]] = \"this is in i[\\\"nice\\\"]\";\n```\n\n### Vec3\nVec3 is a simple type intended to bring glm::vec3 into KataScript as a first class type. Since KataScript is designed for game engine integration, a native Vec3 is convenient. Vec3 is created with the `vec3()` function, individual members (x,y,z) are accessed with list acess.\n\n```c#\nv = vec3(1,2,3);\nprint(v[0]);\n// prints: 1.000000\nv[1] = 10.0; // currently does not work\nv = vec3(v[0], 10.0, v[2]); // current way to set members\n```\n\n## Classes\nA class is a multiply inheritable object. Declare a class with the class keyword.\n\nIn order to use a class, you need a `constructor`, which is the function to create and return instances of your struct. To create a constructor, simply create a function with the same name as the struct that it's in. The constructor can take any number of arguments, and returning the instance is automatically handled by the language runtime, so all you need to do is set the state of the object and you're good to go.\n\n```c#\nclass person {\n    var name;\n    var age;\n    var hobby;\n    func person(n, a, h) {\n        name = n;\n        age = a;\n        hobby = h;\n    }\n    func wouldLike(other) {\n        return hobby == other.hobby;\n    }\n    func greet() {\n        print(\"Hey I'm \" + name + \", age \" + age + \", and my hobby is \" + hobby);\n    }\n}\nvar me = person(\"Garrett\", 28, \"programming\");\nme.greet();\n// prints: Hey I'm Garrett, age 28, and my hobby is programming\nprint(me.wouldLike(person(\"You\", 0, \"programming\")));\n// prints: 1 (aka true)\n```\n\n### Inheritance\nA class can inherit from any number of other classes. The official inheritance operator is `-\u003e` but you can use any token or series of tokens you want. When inheriting from multiple parent classes, sperate the names with `,`\n```c#\nclass xx { \n    var x; \n    func xx(_x) { \n        x = _x; \n    } \n    func add(_x, _y) { \n        x += _x; y += _y; \n    } \n}\nclass yy { \n    var y; \n    func yy(_y) { \n        y = _y; \n    } \n    func sqr() { \n        return x * y; \n    } \n}\n// You get the functions and variables of each parent class (but not the constructors)\n// in event of name collisions, last one in wins\nclass prexy -\u003e xx, yy { \n    func prexy(_x, _y) { \n        x = _x; y = _y; \n    } \n}\n// You get the inherited parents too\nclass xy -\u003e prexy { \n    func xy(_x, _y) { \n        x = _x; y = _y;\n    } \n}\na = xy(4,5.0); \nb = copy(a); \nb.add(\"a\",\"b\"); \nc = a.sqr(); \na.add(4,5); \nd = a.sqr(); \ne = a.x; \nf = a.y;\nprint(a);\n// prints:\n// xy:\n// `x: 8`\n// `y: 10.000000`\n// `add: add`\n// `sqr: sqr`\nprint(b);\n// prints:\n// xy:\n// `x: 4a`\n// `add: add`\n// `y: 5.000000b`\n// `sqr: sqr`\nprint(c);\n// prints: 20.000000\nprint(d);\n// prints: 80.000000\nprint(e);\n// prints: 8\nprint(f);\n// prints: 10.000000\n```\n\n## Errors\nIf an error is detected, evaluation will be halted (for the current line in interpereted mode). Error detection is currently basic and some errors will result in undefined behaviour instead.\n\n### Bad Comparison\n```c#\nj = 3;\nprint(j \u003e 5);\n// prints:  0\nj = \"7\";\nprint(j \u003e 5);\n// prints: Error: Bad comparison comparing `string 7` to `int 5`\nj = 5;\nprint(++j \u003e \"5\");\n// prints: Error: Bad comparison comparing `int 6` to `string 5`\n```\n\n### Out of bounds access\n```c#\nprint(j[0]);\n// prints: 6\nprint(j[2]);\n// prints: Error: Out of bounds list access index 2, list length 1\n```\n\n### Quote mistmatch\n```c#\ni = \"hmmmm;\n// prints: Error: Quote mismatch at \"hmmmm;\n```\n\n### Non-existant function\n```c#\nnothing();\n// prints: Error: Unable to call non-existant function\n```\n\n### Foreach statement count\n```c#\nforeach(a) {\n// prints: Error: Syntax error, `foreach` requires 2 statements, 1 statements supplied instead\n```\n\n### Incorrect token after else\n```c#\nif (0) else tornado if (1) {}\n// prints: Error: Malformed Syntax: Incorrect token `tornado` following `else` keyword\n```\n\n### Array cannot contain collections\n```c#\na = array([1,2],[2,3]);\n// prints: Error: Array cannot contain collections\n```\n\n----\n\n## Built-in Functions\n\n### Math Operators\n`+`/`+=` -\u003e Adds two values, if either is a collection type, it will concatenate them.\n\n`-`/`-=` -\u003e Subtract one number from another, can be used unary to negate a value.\n\n`*`/`*=` -\u003e Multiply two numbbers.\n\n`/`/`/=` -\u003e Divide one number by another.\n\n`%` -\u003e Modulo operation on two numbers.\n\n`++` -\u003e Prefix increment.\n\n`--` -\u003e Prefix decrement.\n\n`=` -\u003e Assign one value to another.\n\n`!` -\u003e Prefix Boolean Not\n \n### Comparison Operators\nNote: these all throw an error if you compare a collection to a number.\n\n`==` -\u003e Compare two values for equality, collections are compared element by element, so \"hi\" == [\"h\", \"i\"]\n\n`!=` -\u003e Same as above but opposite result\n\n`\u0026\u0026` -\u003e True if both values are truthy\n\n`||` -\u003e True if neither value is truthy\n\n`\u003c`, `\u003c=`, `\u003e`, `\u003e=` -\u003e Compare less/greater than. Strings are compared lexographically, and lists are compared by length\n\n### Alias Functions\nAlias functions are functions that are called by language constructs\n\n`identity(x)` -\u003e Takes x as a reference and then returns that reference. Parenthesis used to denote order of operations use this function to enforce ... order of operations.\n\n`listindex(collection, n)` -\u003e Returns the `n`th element of a collection, throws errors if `n` is out of bounds, converts the collection to a dictionary if `n` is not an int. Called by square braket index operator.\n\n`applyfunction(name/func, {class}, ...)` -\u003e Applies the function (by string name or function value) to the arguments. If the first arg is a class, then it will look for a member function on the class before looking for a standard free function.\n\n### Typecast Functions\n`int(x)` -\u003e Converts `x` to int\n\n`float(x)` -\u003e Converts `x` to float\n\n`vec3(x, y, z)` -\u003e Create a Vec3 from `x`, `y`, and `z`\n\n`string(x)` -\u003e Converts `x` to string\n\n`array(x...)` -\u003e Create an array containing `x` and any other arguments supplied\n\n`list(x...)` -\u003e Create a list containing `x` and any other arguments supplied\n\n`toarray(x)` -\u003e Converts `x` to array\n\n`tolist(x)` -\u003e Converts `x` to list\n\n`dictionary(x)` -\u003e Create a dictionary using collection `x` as a source\n\n### Other Functions\n`print(s)` -\u003e Prints a string representation of `s` to the console\n\n`typeof(t)` -\u003e Returns a string representing the type of `t`\n\n`copy(x)` -\u003e Create a copy of `x`\n\n`getline()` -\u003e Returns a string once it has been entered into the console\n\n`split(str, findstr)` -\u003e Returns an array of strings cut from `str` using `findstr` as boundaries\n\n`sqrt(x)` -\u003e Returns the square root of `x`\n\n`pow(x, n)` -\u003e Returns `x^n`\n\n`sin(x)` -\u003e Returns sine of `x`\n\n`cos(x)` -\u003e Returns cosine of `x`\n\n`tan(x)` -\u003e Returns tangent of `x`\n\n`clock()` -\u003e Returns the current time in nanoseconds since the epoch as an int\n\n`timesince(x)` -\u003e Returns the time since `x` as a float of seconds where `x` is an int of nanoseconds since the epoch\n\n`getduration(a,b)` -\u003e Returns the time between `a` and `b` as a float of seconds where `a` and `b` are ints of nanoseconds since the epoch\n\n`length(c)` -\u003e Returns teh size of the collection `c`\n\n`find(c, item)` -\u003e Returns the index in `c` where item exists, or null if no match exists\n\n`contains(c, item)` -\u003e Returns true if the item exists in `c` or false if no match exists\n\n`erase(c, n)` -\u003e Erase the item at index `n` from collection `c`\n\n`range(c, a, b)` -\u003e Returns a new collection from a range from indexes `a` to `b` in collection `c`\n\n`range(a, b)` -\u003e Returns a new array with int or float values ranging from `a` to `b`. `b` can be larger or smaller than `a`.\n\n`pushback(c, item)` -\u003e Adds `item` to the end of collection `c`\n\n`popback(c)` -\u003e Erases the item at the end of collection `c`\n\n`sort(c)` -\u003e Sorts collection `c`\n\n`map(c, f)` -\u003e Applies function `f` to each element of `c` and returns a list of the results\n\n`fold(c, f, initial)` -\u003e Folds function `f` over each element of `c` into `initial` and returns the result\n\n### Precedence\nFrom lowest to highest this is the precedence of operations in KataScript:\n\nAssignment,\n\nComparison,\n\nAddition/Subtraction,\n\nMultiplicaton/Division/Modulo,\n\nIncrement/Decrement,\n\nand finally Parenthesis/Function Calls.\n\n\n----\n\n## Examples\n### Hello World\n```c#\nprint(\"hello world\");\n```\n\n### Fizzbuzz\n```c#\nfunc fizzbuzz(n) {\n  for(i=1;i\u003c=n;i++) { \n    if (i % 15 == 0) { \n      print(\"fizzbuzz\"); \n    } else if (i % 3 == 0) { \n      print(\"fizz\"); \n    } else if (i % 5 == 0) { \n      print(\"buzz\"); \n    } else { \n      print(i);\n    } \n  }\n}\n```\n\n### Fizzbuzz With Map\n```c#\nfunc fizz(n) {\n    if (n % 15 == 0) {\n        return \"FizzBuzz\";\n    } else if (n % 3 == 0) {\n        return \"Fizz\";\n    } else if (n % 5 == 0) {\n        return \"Buzz\";\n    }\n    return n;\n}\nfunc fizzbuzz(n) {\n    foreach(result; range(1,n).map(fizz)) {\n        print(result);\n    }\n}\n```\n\n### The Fibonacci Series\n```c#\n// print all Fibonacci numbers up to c\nfunc printfibs(c) {\n  i = 0;\n  j = 1;\n  while(i\u003cc) { \n    print(i); \n    i += j; \n    swap(i, j);\n  }\n}\n// recursively find Fibonacci number at index n:\nfunc fib(n) {\n    if (n \u003c 2) {\n        return n;\n    }\n    return fib(n-1) + fib(n-2);\n}\n```\n\n### Functional Programming\n```c#\nfuncs = [print, printfibs, fizzbuzz];\nvals = [1,2,3,4,5,6];\nforeach(v; vals) {\n  print(\"operating on \" + v);\n  foreach(f; funcs) {\n    f(v);\n    print();\n  }\n}\n```\n\n```c#\nfunc sub1(n) { \n  return n-1; \n}\nforeach(i; map([1,2,3,4], sub1)) { \n  print(i); \n}\n```\n\n----\n\n## C++ Integration\nKataScript is a header only library. To include KataScript into your project simply put the headers in /src/ into your project, `#define KATASCRIPT_IMPL` in exactly `1` cpp file, and then #include KataScript.hpp wherever you need. Note that KataScript's implementation uses C++20, so you need g++9/MSVC19 or higher to compile it.\n\n```c++\n#define KATASCRIPT_IMPL\n#include \"../../KataScript/src/Library/KataScript.hpp\"\n```\n\n### Invoke C++ From KataScript\nIf we want to call C++ code from inside the script, we can register the code as a function any time after calling the KataScriptInterpreter constructor; (note that the function will be placed in the current scope)\n\nHere's a function to wrap for the example: (in C++)\n```c++\nint integrationExample(int a) {\n  return a * a;\n}\n```\n\nThen here's how we register it for use inside of KataScript: (note, this will overwrite any existing function with the same name, so you can use that to redirect the print function for example)\n```c++\nKataScript::KataScriptInterpreter interp;\nauto newfunc = interp.newFunction(\"integrationExample\", [](const KataScript::KSList\u0026 args) {\n  // KataScript doesn't enforce argument counts, so make sure you have enough\n  if (args.size() \u003c 1) {\n    return std::make_shared\u003cKataScript::KSValue\u003e();\n  }\n  // Dereference argument\n  auto val = *args[0];\n  // Coerce type\n  val.hardconvert(KataScript::KSType::INT);\n  // Call c++ code\n  auto result = integrationExample(val.getInt());\n  // Wrap and return\n  return std::make_shared\u003cKataScript::KSValue\u003e(result);\n});\n```\n\nNow we can call that function from inside our scripts.\n\n### Invoke KataScript From C++\nWe can directly call a KataScript function from C++ using the value returned by newFunction().\n```c++\nauto varRef = interp.callFunction(newfunc, 4);\n```\n\nWe can also send commands from C++ into KataScript using the readLine or evaluate functions.\n```c++\ninterp.readLine(\"i = integrationExample(4);\");\n```\n\nNow `i` contains `16` and is an int.\nIf we want to pull that value out, we can do that too!\n\n```c++\nauto varRef = interp.resolveVariable(\"i\");\n \n// visit style\nstd::visit([](auto\u0026\u0026 arg) {std::cout \u003c\u003c arg; }, varRef-\u003evalue);\n   \n// if the type is known\nint i = varRef-\u003egetInt();\n  \n// switch style\nswitch (varRef-\u003etype) {\ncase KataScript::KSType::INT:\n  std::cout \u003c\u003c varRef-\u003egetInt();\n  break;\ncase KataScript::KSType::FLOAT:\n  std::cout \u003c\u003c varRef-\u003egetFloat();\n  break;\ncase KataScript::KSType::STRING:\n  std::cout \u003c\u003c varRef-\u003egetString();\n  break;\n}\n```\n\nWe can also create KataScript classes from C++\n```c++\n// create a KataScript class from C++:\ninterp.newClass(\"beansClass\", { {\"color\", std::make_shared\u003cKataScript::KSValue\u003e(\"white\")} }, { \n    // constructor is required\n    {\"beansClass\", [](const KataScript::KSList\u0026 vars) {\n        if (vars.size() \u003e 0) {\n            interp.resolveVariable(\"color\") = vars[0];\n        }\n        return std::make_shared\u003cKataScript::KSValue\u003e();\n        } },\n    // add as many functions as you want\n    {\"changeColor\", [](const KataScript::KSList\u0026 vars) {\n        if (vars.size() \u003e 0) {\n            interp.resolveVariable(\"color\") = vars[0];\n        }\n        return std::make_shared\u003cKataScript::KSValue\u003e();\n        } },\n    {\"isRipe\", [](const KataScript::KSList\u0026) {\n        auto\u0026 color = interp.resolveVariable(\"color\");\n        if (color-\u003etype == KataScript::KSType::String) { return std::make_shared\u003cKataScript::KSValue\u003e(color-\u003egetString() == \"brown\"); }\n        return std::make_shared\u003cKataScript::KSValue\u003e(false);\n        } },\n    });\n\n// use the class\ninterp.readLine(\"bean = beansClass(\\\"grey\\\");\");\ninterp.readLine(\"ripe = bean.isRipe();\");\n\n// get values from the interpereter\nauto beanRef = interp.resolveVariable(\"bean\");\nauto ripeRef = interp.resolveVariable(\"ripe\");\n\n// read the values!\nif (beanRef-\u003etype == KataScript::KSType::Class \u0026\u0026 ripeRef-\u003etype == KataScript::KSType::Int) {\n    auto colorRef = beanRef-\u003egetClass()-\u003evariables[\"color\"];\n    if (colorRef-\u003etype == KataScript::KSType::String) {\n        std::cout \u003c\u003c \"My bean is \" \u003c\u003c beanRef-\u003egetClass()-\u003evariables[\"color\"]-\u003egetString() \u003c\u003c \" and it is \" \u003c\u003c (ripeRef-\u003egetBool() ? \"ripe\" : \"unripe\") \u003c\u003c \"\\n\";\n    }\n}\n```\n\n### C++ Types and Methods\nAll KataScript C++ types are in the KataScript namespace. KataScript uses std::shared_ptr to count references, so functions will generally return a shared pointer to the actuall value. Any time you see a type like `KSThingRef` that means it's an alias for `shared_ptr\u003cKSThing\u003e`\n\nenum KSType -\u003e This is our type flag. Options are `NONE`, `INT`, `FLOAT`, `FUNCTION`, `STRING`, and `LIST`.\n\nstruct KSValue -\u003e This struct represents a boxed value. If you pull data out of the KataScript environment it will be wrapped in this type. Uses an std::variant to store the actual value so you can use the visitor pattern if you want.\n* string getPrintString() -\u003e Get a string representing what printing this value would print\n* int\u0026 getInt() -\u003e Gets a reference to the internal value as an int\n* float\u0026 getFloat() -\u003e Gets a reference to the internal value as a float\n* KSFunctionRef\u0026 getFunction() -\u003e Gets a reference to the internal value as a function reference\n* string\u0026 getString() -\u003e Gets a reference to the internal value as a string\n* KSList\u0026 getList() -\u003e Gets a reference to the internal value as a list\n* KSDictionary\u0026 getDictionary() -\u003e Gets a reference to the internal value as a dictionary\nAll KataScript math operations are implemented by overloading C++ operators on KSValues, so math operations on KSValues in C++ will produce the same results as those operations within KataScript\n\nalias KSList -\u003e A KSList is just an std::vector of std::shared_ptr to KSValue. This is the data backing for the List type as well as defining the format for function arguments\n\nalias KSDictionary -\u003e A KSDictionary is just an std::unordered_map\u003csize_t, std::shared_ptr\u003cKSValue\u003e\u003e. This is the data backing for the Dictionary type, using 64 bit hashes (size_t) as a key\n\nalias KSLambda -\u003e This this the function signature of all KataScript functions. It's an std::function that takes in a const reference to a KSList and returns a shared_ptr to a KSValue\n\nclass KataScriptInterpreter -\u003e This is the main class and represents a fully contained KataScript environment. It is instantiated through the default constructor, and will RAII itself with a default destructor. You can run as many instances as you want side by side with no issues.\n* KSFunctionRef\u0026 newFunction(const string\u0026 name, const KSLambda\u0026 lam) -\u003e Adds or overrides a C++ lambda as a KataScript function and returns a reference to that function\n* KSValueRef callFunction(const KSFunctionRef fnc, ...) -\u003e Call a KataScript function. Arguments are a reference to a KataScript function, and then as many arguments to the function as necessary.\n* KSFunctionRef resolveFunction(const string\u0026 name) -\u003e Get a reference to a KataScript function by name\n* KSValueRef\u0026 resolveVariable(const string\u0026 name) -\u003e Retrieve a KataScript value by variable name\n* void readLine(const string\u0026 text) -\u003e Evaluate a line of text as KataScript\n* void evaluate(const string\u0026 script) -\u003e Evaluate a multi-line KataScript\n\n### C++ Usage Pattern\nUsing the methods of KataScriptInterpreter, we have a simple pattern for embeded scripting:\n1. Initialize a KataScriptInterpreter\n2. Register any native functions you want by wrapping them in a KSLambda and submitting that to newFunction()\n3. Read your scripts into strings and evaluate() or readLine() them into the KataScriptInterpreter to set up functions and inital state\n4. Call into KataScript with callFunction() (or readLine()/evaluate() followed by a resolveVariable()) whenever you want to run KataScript functions.\n\n----\n\n## Future Features Roadmap\nThese are things that are planned additions:\n- Near term\n* Expand the modules system (currently it just stores all the standard functions in one module) to support optional modules which can be be whitelisted/blacklisted on the C++ embedded side and imported on the KataScript side, imports of non-allowed modules will probably result in an error.\n- Mid term\n* async/threading\n- Long term\n* Integrate with llvm to produce executables\n","funding_links":[],"categories":["Uncategorized","C++"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrwhale%2FKataScript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrwhale%2FKataScript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrwhale%2FKataScript/lists"}