(qscript is currently under development. Not all features listed in this document may be currently implemented. To see project status, please read 'STATUS.md'.)
Contents:
- What is qscript?
- How qscript works
- Using qscript
- Why make this?
- Scripting language
- qscript standard library
- Formal grammar
- Internal stuff
- Pre-defined values
- Glossary of terms
This library is designed to create a persistent-state world of generic objects with arbitrary code injection/ejection, inter-object relationships that automatically update, and a sensible interface between the scripting environment and your project.
qscript is useful for projects that need to do things like:
- Create a persistent game world with thousands of objects over an indefinite amount of time with guaranteed data consistency
- Accurately and efficiently maintain the positions of elements in a web document using a complex stylesheet
- Create dynamic polymorphic objects with no strict definition
Q. "What does the 'q' in 'qscript' stand for?"
A. "qscript."
To use qscript, your project must first define a scheme that will create a world which contains resources and objects.
Resources are scripts defined by files using the ".qs" extension. qscript uses its own scripting language designed specifically to accomplish the project's goals. It strives to be a functional language to ensure consistent results and employ a minimal set of grammatical rules to maintain simplicity.
Objects are containers for properties and are instantiated at runtime. Their properties are defined through a chain of rlinks (links to resources) that can be modified and rearranged dynamically.
All object property modifications are non-destructive and pushed onto a stack so they can be safely reverted. Rlink chains are modified by unwinding (rolling back) to the point of modification, injecting (inserting) or ejecting (removing) the desired script, then rewinding (re-executing scripts that have been unwound). Rlinks in the rlink chain are ordered by their priority (an arbitrary integer value) from lowest to highest.
The world tracks all object influences (properties/variables read from anything other than itself) and ensures that influenced objects update properly when the external value is changed.
Contents:
The resources and C code below can be found in the example program "examples/objdump" in this repository.
In the following tutorial, we'll be creating a program that instantiates a player object as the groundwork for a tiny RPG. The player will have some base stats, a class, some equipment, and some buffs/debuffs attached from the start.
Here is our desired rlink chain:
Priority | Resource | Effect |
---|---|---|
0 | player_base |
Define base values for all properties |
10 | class_wizard |
Modify stats and abilities to turn this character into a wizard |
20 | purple_robe_on |
Change appearance and stats |
20 | magic_wand_on |
Increase strength and grant a new ability |
30 | buff_invisible |
(Temporary) modify appearance and increase sneaking to 100% |
40 | too_hot |
(Applied from environment) Character is slower and dumber |
Before creating our object and implementing qscript into your project, let's define all of the resources listed above in a '.qs' resource file.
(from 'examples/objdump/my_resources.qs'):
player_base {
# set base properties.
= (.str, 10.00); # strength
= (.def, 10.00); # defense
= (.int, 10.00); # intelligence
= (.agi, 10.00); # agility
= (.class, "none"); # we don't have a class yet.
= (.color, "beige"); # character is super bland.
= (.skills, []); # our skills is an empty list.
= (.sneak, 0.00); # we're not very sneaky.
}
class_wizard {
= (.class, "wizard"); # define our class:
*= (.str, 0.50); # weak,
*= (.def, 0.50); # fragile,
*= (.int, 2.00); # but super smart,
+= (.skills, "spell_fire"); # and with a spell.
}
purple_robe_on {
= (.color, "purple"); # we're purple now.
+= (.def, 5.00); # small buff to defense,
+= (.int, 10.00); # and a big one to intelligence.
}
magic_wand_on {
+= (.str, 3.00); # slight strength increase,
if (== (.class, "wizard"), # if we're a wizard...
+= (.skills, "spell_invisible")); # ...add a new spell.
}
buff_invisible {
= (.color, "clear"); # can't see us!
= (.sneak, 100.00); # 100% sneaking
}
too_hot {
*= (.agi, 0.75); # 75% agility
*= (.int, 0.75); # 75% intelligence
}
To create the object described above, we'll need to:
- create a scheme for our qscript world,
- instantiate a blank object,
- inject rlinks into the object's rlink chain, and
- update our world to finish our object.
(from 'examples/objdump/main.c'):
/* create our scheme, load its resources, and update changes. */
qs_scheme_t *scheme = qs_scheme_new ();
qs_parse_file (scheme, "my_resources.qs");
qs_scheme_update (scheme);
/* instantiate our player and add rlinks to its resource chain. */
qs_object_t *obj = qs_object_new (scheme, "player");
qs_rlink_inject (obj, qs_resource_get (scheme, "player_base"), 0);
qs_rlink_inject (obj, qs_resource_get (scheme, "class_wizard"), 10);
qs_rlink_inject (obj, qs_resource_get (scheme, "purple_robe_on"), 20);
qs_rlink_inject (obj, qs_resource_get (scheme, "magic_wand_on"), 20);
qs_rlink_inject (obj, qs_resource_get (scheme, "buff_invisible"), 30);
qs_rlink_inject (obj, qs_resource_get (scheme, "too_hot"), 40);
/* update changes again so 'obj' is run. */
qs_scheme_update (scheme);
/* (do everything we want with our object) */
...
/* clean-up time! free all objects, resources, and the scheme itself. */
qs_scheme_free (scheme);
Executing the test program 'objdump' via 'objdump.sh' will describe the resulting object like so:
> ./objdump.sh
player:
str (float) = 8
def (float) = 10
int (float) = 22.5
agi (float) = 7.5
class (string) = "wizard"
color (string) = "clear"
skills (list) = ["spell_fire", "spell_invisible"]
sneak (float) = 100
One of my favorite type of games to make are text-based multiplayer RPGs called MUDs (multi-user dungeons), which are early forerunners to MMOs. These are reasonable projects to tackle because you don't need to make a million assets and the game runs 100% server-side. For one MUD I was working on, my goal was to have a persistent world with as many of its resources put into text files as possible so I could define new monsters, classes, and abilities without hard-coding anything in. The purpose of that was to make edits quick and easy without recompilation and allow hot-loading so the server would never have to reboot. If I wanted to add stuff in or make changes, I could log into the server, load the new files, and play right away. Neat!
Now, if the server was going to run potentially for months at a time, small bugs here and there would break objects, maps, and (worst of all) players, requiring some hands-on fixes when the world state gets corrupted. MMOs are very complex and only get bigger over time, so as the world and player base grows, the likelihood that something will get bugged-out is off the charts and such bugs would be difficult if not impossible to track. There are too many examples to list, but here are a few anyway:
- Buffs/debuffs not turning themselves off properly,
- Temporary stat modifiers not reverting correctly,
- Triggers for quests not activating or deactivating,
- Puzzles not resetting properly,
- Item duplication or destruction bugs,
...and so on.
qscript aims to avoid these potential problems by developing a layer of object management that only performs non-destructive object modifications, eliminating the possibility of object state corruption. Any change made to an object must be guaranteed to be revertible, which means all property modifications must be pushed onto a stack that can be safely popped later. It works like this: If a player acquires a Quad Damage buff, it will push a small script that multiplies damage output by 4. When Quad Damage wears off, that script and its modifications are popped, reverting damage output back to normal.
In addition to preventing state corruption, qscript also strives to ensure that multiple buffs would applied in a consistent, predictable order. Let's say there's a buff called Extra Damage that adds 10 to your character's damage output. If Quad Damage is also applied, which executes first? For a character that inflicts 25 damage per hit, the script order makes a big difference for the resulting damage:
- Quad Damage, then Extra Damage:
damage = ((25 * 4) + 10) = 110
- Extra Damage, then Quad Damage:
damage = ((25 + 10) * 4) = 140
Let's assume the first behavior is desired. To make sure this happens, each script is given a number called a priority that determines its order of execution. Quad Damage has a lower priority than Extra Damage which means its effects are always applied first.
(keep writing...)
Contents:
- Values, actions, and function calls
- Simple real primitives
- Complex real primitives
- Abstract primitives
- Examples
qscript's scripting environment strives to stay as grammatically simple as possible while remaining flexible and powerful. The language is used to define resources and their scripts in the form of a single code block. Each resource can be:
- instantiated as the base of an object,
- injected into an object's rlink chain as an rlink, or
- automatically instantiated immediately after compilation as a global object.
At first glance, a simple resource definition resembles that of a C-family programming language:
main {
echo ("Hello, world!");
return (0);
}
There are, however, some important distinctions. There are no built-in procedures for code flow or math; each of these features are defined as functions that need to be invoked with a typical function's syntax. Notice the return (0);
line above. Same same applies for functions like if()
, for()
, +()
, ==()
, and =()
. For specific usage on these functions, please refer to the qscript standard library section.
All code is composed of values followed by zero or more actions. When a value is encountered, it is first evaluated, a process which dereferences variables, properties, and executes blocks until a real primitive is found. If a value has an action, the evaluation is inputted into that action whose evaluation is fed into the next action and so on. The final evaluation is then returned to the value's caller.
The most common action is a function call, which interprets its input as a function name and attempts to execute it. Function calls are declared with a set a parentheses containing a comma-separated list of values that are passed to the function as parameters. A function name can be any string matching either an internal function or a resource.
The following are all valid function calls that produce the same result:
# Each evaluation will print "foo" followed by a newline.
echo ("foo"); # "echo" is a string matching a function.
"echo" ("foo"); # This is equally valid.
+ ("ec", "ho") ("foo"); # +() returns "echo" which is then called by the next action.
{ "echo"; } ("foo"); # This block will return "echo" which is also called.
if (1, "echo") ("foo"); # if() returns the matching case, which is "echo".
All values are ultimately stored as real primitives. Real primitives are classified as either simple or complex. Simple primitives contain all their data directly in the value structure qs_value_t
and require no extra processing.
Type | Description | Declaration |
---|---|---|
undefined | Placeholder type for uninitialized variables and errors. | undefined |
string | Any text value. | string , "string" , 'string' |
int | Integer value. | [+/-]123456 |
float | Floating-point decimal value. | [+/-]123456.789 |
Note: Single or double-quoted strings can be combined into a single string thusly:
echo ("This " "is " "one " 'big ' 'string ');
Contents:
Complex primitives have unique characteristics that may contain additional processing or memory allocation.
Type | Description | Declaration |
---|---|---|
char | Single character. | 'a' |
list | Zero or more values that can be indexed. | [] , [1, 2, 3] |
object | Reference to an instantiated object for property look-ups. | @object , @@global-object |
The char primitive can be modified by mathematical operations as if it's ASCII character value. They can also refer to a character belonging to a string indexed by [<value>]
just like a C-string. In that case, modifying the value will update the string it belongs to.
+ ('a', 1); # evaluates to 'b'
- ('a', 32); # evaluates to 'A'
= ($string, "wow"); # define a string 'wow'...
= ($string[0], 'c'); # ...and turn it into 'cow'
The list primitive can be indexed by [<value>]
in the same way as a string. In that case, modifying the value will update the list it belongs to. Lists can also have their contents used as function call parameters with a preceding ~
character. This is called unfolding.
= ($list, [1, 2, 3]); # A list with three numbers.
= ($math, + (~$list)); # Same as `= ($math, + (1, 2, 3));`
echo ($math); # prints '6'
= ($list[2], 30); # List becomes `[1, 2, 30]`
echo (+ (~$list)); # prints '33'
The object primitive points to an object by either its name or unique ID. When evaluated, no lookup is performed directly - only by the action that requires it. If the object cannot be found, the action will typically return the <no object>
error.
The primary purpose of interacting with objects is to read their properties. Properties can only be read from other objects, not modified. For more information on properties, refer to Abstract Primitives -> properties.
@my_object { # Instantiate resource with the name '@my_object'.
= (.color, "blue"); # Set property 'color' to 'blue'.
= (.shape, "sphere"); # Set property 'shape' to 'sphere'.
}
copy_object { # This script, when injected, will copy properties from @my_object.
= ($obj, @@my_object); # The '@' refers to an object named '@my_object'.
= (.color, $obj.color); # Match color of object.
= (.shape, $obj.shape); # Also match our shape.
= ($obj.shape, "box"); # @my_object.shape is read-only; this will report an error.
}
Values can also contain primitives that require execution or referencing during evaluation. These are called abstract primitives.
(continue writing this)
Contents:
Resources injected into objects will typically modify properties.
# Multiply strength by 4.
buff_quad_damage {
*= (.str, 4);
}
# Make left-handed people right-handed and vice-versa.
switch_handedness {
if (==(.handed, "left"), =(.handed, "right"), # left ==> right
==(.handed, "right"), =(.handed, "left")); # right ==> left
}
# Change our color to match the color of the room.
buff_chameleon {
# Property '.room' refers to an object such as:
# @room_jungle_entrance
= (.color, .room'.color);
}
Utility functions are resources that take zero or more arguments as inputs and either return a result or perform an operation.
# fibonacci_for (n):
# Calculate and return the nth Fibonacci number using a for() loop.
fibonacci_for {
args ($n);
if (<= ($n, 2),
return (1));
= ($prev, 1);
= ($current, 1);
for (= ($i, 2), < ($i, $n), ++($i), {
= ($tmp, $prev);
= ($prev, $current);
+= ($current, $tmp);
});
}
# echo_indented (space_count, string):
# Echo a string with preceeding spaces.
echo_indented { # Takes (int, string).
args ($indent, $string); # Assign arguments to variables.
= ($istr, ""); # Initialize indented spaces.
for (= ($i, 0), < ($i, $indent), ++ ($i), # Do this $length times:
+= ($istr, ' ')); # Append a space to $istr
return (echo ($istr, $string)); # Echo/return string w/ indents.
}
# echo_doge ():
# Echo a meme, more nicely-formatted than it deserves to be.
echo_doge {
= ($my_string, "so string, very tokens, wow"); # Let's tokenize a meme.
= ($count, 0); # Keep track of indentation.
for_each (tokenize ($my_string), $token, { # Tokenize.
-= ($token[0], 32); # Capitalize the first letter.
echo_indented (* (2, $count), $token); # Print our token with indents.
++ ($count); # Increment counter.
});
}
# fibonacci_recurse (n):
# Calculate and return the nth Fibonacci number using recursion.
fibonacci_recurse {
args ($n);
if (<= ($n, 1), $n, # Stop at zero and one.
+ ( # Otherwise, return:
fibonacci_recurse (- ($n, 1)), # f(n-1) + f(n-2)
fibonacci_recurse (- ($n, 2))
)
);
}
These resources are designed for instantiation. They set base values and run any initialization scripts they may need.
# Base object used for instantiation of characters.
character_base {
# Base values modified by class and level later.
= (.str, 10.0);
= (.def, 10.0);
= (.agi, 10.0);
= (.max_hp, 50.0);
= (.int, 10.0);
= (.agi, 10.0);
# Some default values that will need additional scripts.
= (.class, "Unemployed");
= (.race, "Being");
= (.gender, "Neutral");
# Variables assigned by an object variable so they can be modified permanently.
= (.level, %level);
= (.exp, %exp);
= (.gold, %gold);
}
# Warrior ready for instantiation.
warrior_base {
# Use 'character_base' as our model.
character_base ();
# Modify stats/properties and turn ourselves into a warrior.
= (.class, "Warrior");
*= (.str, 1.50);
*= (.def, 1.50);
*= (.max_hp, 1.25);
*= (.int, 0.50);
*= (.agi, 0.50);
}
# Global object that stores useful information.
@world {
# Get our global time (in hours).
= ($time, %%time);
# Set a "time of day" phrase for everything to use.
= (.time_of_day,
if (< ($time, 1.00), "midnight",
< ($time, 5.00), "late night",
< ($time, 6.00), "dawn",
< ($time, 9.00), "morning",
< ($time, 12.00), "forenoon",
< ($time, 13.00), "noon",
< ($time, 16.00), "afternoon",
< ($time, 19.00), "evening",
< ($time, 22.00), "dusk",
"night"));
}
Contents:
- Text output
- Math / logical
- Informative
- Assigning / modifying
- Code flow
- Argument processing
- Casting
- Object manipulation
Prints zero or more strings to stdout
. No newline character is printed.
Prints zero or more strings to stdout
. Prints newline character afterwards.
Prints the current resource or a resource identified by <resource>
with nice formatting and syntax highlighting. Used for debugging.
Prints an evaluation of <value>
with proper syntax highlighting identical to print_resource
.
Math functions can be expressed in two ways:
-
Perform a calculation and return the result (
+
,-
,*
, etc). -
Directly modify an lvalue (
+=
,-=
,*=
, etc). An lvalue is any value can that be modified because it is stored by a variable or parameter.
Math functions do not perform type promotion and will always return or store a value whose type is determined by the first argument. This type will be refered to as the operation type for all math descriptions. All proceeding values are interpreted as values of the same type. Exceptions and special features such as concatenating strings or appending to lists via +
/+=
are described in their function descriptions.
Applicable operation types: int, float, string, char, list
Adds two or more values and returns the result.
For operation type string, values are concatenated. For operation type list, the proceeding values are appended as list items. For operation type char, the initial ASCII value is incremented by the integer component of each value. Exceeding the char boundries (>= 1, <= 255) will result in an error.
Applicable operation types: int, float, char
Subtracts one or more values from <value1>
and returns the result.
For operation type char, the initial ASCII value is decremented by the integer component of each value. Exceeding the char boundries (>= 1, <= 255) will result in an error.
Multiplies two or more values and returns the result.
+=
-=
*=
/=
**=
|=
&=
^=
%=
=
++
--
vars
if
return
break
continue
while
for
switch
run
eval
for_each
args
arg
arg_list
int
string
float
char
object
variable
property
new
Contents:
(coming later!)
QS_FUNC
QS_STACK_FUNC
QSV_DEFINE
QS_ARGV
QS_ARGS
QS_ARGF
QS_ARGI
QS_ARGL
QS_ARGO
QS_ARG_ERROR
QS_RETS
QS_RETF
QS_RETI
QS_RETC
QS_RETURN
QS_BREAK
QS_CONTINUE
(coming later!)
qs_arg_float
qs_arg_int
qs_arg_string
qs_arg_value
qs_arg_list
qs_arg_value
qs_execute_get_block
qs_execute_get_call
qs_execute_pop
qs_execute_push
qs_func_break
qs_func_continue
qs_func_error
qs_func_return
qs_func_run
qs_list_copy
qs_list_free
qs_list_internalize
qs_list_new
qs_list_value
qs_object_free
qs_object_get
qs_object_get_by_id
qs_object_instantiate
qs_object_new
qs_parse_content
qs_parse_init
qs_parse_file
qs_print_action
qs_print_list
qs_print_resource
qs_print_value
qs_property_get
qs_property_value
qs_resource_get
qs_resource_get_auto_instance
qs_resource_get_by_id
qs_return_char
qs_return_float
qs_return_int
qs_return_string
qs_return_value_new
qs_rlink_is_child_of
qs_rlink_pop
qs_rlink_push
qs_rlink_push_at
qs_rlink_unwind
qs_rlink_wind
qs_scheme_cleanup
qs_scheme_free
qs_scheme_funcs
qs_scheme_get_func
qs_scheme_heap_value
qs_scheme_new
qs_scheme_update
qs_value_can_modify
qs_value_cleanup
qs_value_cleanup_self
qs_value_contains
qs_value_copy
qs_value_copy_const
qs_value_init
qs_value_length
qs_value_list
qs_value_list_internalize
qs_value_lvalue
qs_value_object
qs_value_property
qs_value_read
qs_value_restring
qs_value_truth
qs_value_type
qs_value_update_from_string
qs_value_variable
qs_variable_contains
qs_variable_get
qs_variable_value
(<resource>)*
The character #
can be used when any value, resource, or action is expected.
All text following #
will be ignored by the parser.
[@]<string> <block>
Defines a resource named <string>
containing code <block>
.
The '@' character indicates that the resource is to be automatically instantiated as an object named '@resource-name'.
'{'
<value>1; # Examples:
<value>2; # = ($variable, 10);
... # echo ("My variable is: ", $variable);
<value>n; # $variable; <--- Last value is always returned
'}'
Creates a series of zero or more values for evaluation.
Block contents are immediately evaluated whenever they are referenced by
values or call actions. They return the last evaluation, which includes the
value passed to return()
, break()
, or continue()
. If the block
contains zero values, QSV_UNDEFINED
is returned.
[~]<primitive> <action>1 ... <action>n
Universal symbol for literal primitives, function calls, and other actions.
The '~' indicates that the result is to be unfolded into the action from
which it is called. This requires the evaluation to be of type list
,
otherwise it will report an error. The contents of the list will be inserted
into the parameter list of the action from which it was called.
Matches the first of the following, starting from the top:
<int>
<float>
<variable>
<property>
<list>
<block>
<char>
<object>
<undefined>
<string>
Regular expression: [-+]?[0-9]+
(One or more digits optionally preceded by '-' or '+'.)
Creates an integer value.
Regular expression: [-+]?[0-9]+\.[0-9]+
(One or more digits optionally preceded by '-' or '+', followed by a decimal
point and one or more digits.)
Creates a floating-point value.
Regular expression: [\\$]+[a-zA-Z0-9_]+
(One or more $
characters followed by one or more alphanumeric/underscore
characters.)
Creates a reference to a block- or rlink-scope variable.
A single $
refers to a block scope variable. Two ($$
) characters refers
to an rlink scope variable.
If the variable is not found in the current scope, it will be created.
.<value>[']
Creates a reference to a property belonging to the current object's.
Can be used as an <action>
, in which case it creates a reference to a property
belonging to the evaluated parent value.
The optional quote acts as a closing parenthesis, allowing actions to
be called on the evaluation of the property.
If omitted, all proceeding actions will be considered belonging to <value>
.
If called as an action, an error will be reported if the evaluation of the
parent value is not of type <object>
.
'[' <value>1, <value>2, ... <value>n ']'
Creates a list of zero or more values.
Values contained in the list are not evaluated until they are indexed.
Regular expression: '.'
(Any single character surrounded by single quotes.)
Regular expression: [@]+[a-zA-Z_]+
(One or more @
characters followed by one or more alphanumeric/underscore
characters.)
A single @
refers to externally instantiated objects. Two (@@
) refers to
an auto-instantiated object from a resource.
Exact string match: undefined
Evaluates to QSV_UNDEFINED
. Does not create a new value.
Matches the first of the following, starting from the top:
<call>
<index>
<property>
(<value>1, <value>2, ... <value>n)
Executes a resource, function, or list, supplying zero or more parameters.
Resources are attempted to be evaluated first. Any resource can be executed,
including auto-instantiated resources. Parameters are read as arguments via
the arg()
, args()
, and arg_list()
qfuncs.
Any function supplied by the scheme, including the standard, will then be executed.
If the parent evaluation is type <list>
, it is considered a lambda
functions and all list elements will be evaluated as if they are a resource.
Internal calls to arg()
, args()
, and arg_list()
will pull arguments from
the lambda function's parameter list. It is recommended that list elements be
defined as <block>
s for the sake of formatting consistency.
'[' <value> ']'
**Returns an element of a <list>
or a single character in a **<string>
.
Indexes are considered lvalues and can be assigned with any assignment
function. However, indexing <string>
s is very strict; the indexed value
will always be of type <char>
and only values valid for assignment must
safely cast to type <char>
.
(See <property>
definition under <primitive>
.)
(coming later!)
qs_object_t
qs_value_t
qs_resource_t
qs_rlink_t
qs_scheme_t
qs_func_t
qs_variable_t
qs_execute_t
qs_list_t
qs_action_t
qs_stack_t
qs_property_t
qs_modify_t
QSCRIPT_INVALID
QSCRIPT_UNDEFINED
QSCRIPT_ROOT
QSCRIPT_COMMENT
QSCRIPT_RESOURCE
QSCRIPT_RFLAGS
QSCRIPT_RNAME
QSCRIPT_BLOCK
QSCRIPT_LIST
QSCRIPT_OUTER_LIST
QSCRIPT_VALUE
QSCRIPT_VFLAGS
QSCRIPT_PRIMITIVE
QSCRIPT_OUTER_BLOCK
QSCRIPT_SEPARATOR
QSCRIPT_STRING
QSCRIPT_SIMPLE_STRING
QSCRIPT_COMPLEX_STRING
QSCRIPT_NUMBER
QSCRIPT_FLOAT
QSCRIPT_INT
QSCRIPT_VARIABLE
QSCRIPT_ACTION
QSCRIPT_CALL
QSCRIPT_INDEX
QSCRIPT_CHAR
QSCRIPT_OBJECT
QSCRIPT_PROPERTY
QS_ACTION_CALL
QS_ACTION_INDEX
QS_ACTION_PROPERTY
QS_SCOPE_AUTO
QS_SCOPE_RLINK
QS_SCOPE_BLOCK
QS_EXE_LAMBDA
QS_EXE_FUNC
QS_EXE_RESOURCE
QS_EXE_BLOCK
QS_EXE_LOOP
Name | Type | Value |
---|---|---|
QSV_ZERO |
int | 0 |
QSV_ONE |
int | 1 |
QSV_INVALID_TYPE |
undefined | "<invalid_type>" |
QSV_NOT_VARIABLE |
undefined | "<not_variable>" |
QSV_NOT_PROPERTY |
undefined | "<not_property>" |
QSV_CANNOT_MODIFY |
undefined | "<cannot_modify>" |
QSV_NOT_FUNC_CALL |
undefined | "<not_func_call>" |
QSV_INVALID_INDEX |
undefined | "<invalid_index>" |
QSV_NO_INDEX |
undefined | "<no_index>" |
QSV_INVALID_SUB_FUNC |
undefined | "<invalid_sub_func>" |
QSV_NOT_ENOUGH_ARGS |
undefined | "<not_enough_args>" |
QSV_INVALID_FUNC |
undefined | "<invalid_func>" |
QSV_INVALID_OPER |
undefined | "<invalid_oper>" |
QSV_DIVISION_BY_ZERO |
undefined | "<division_by_zero>" |
QSV_MOD_BY_ZERO |
undefined | "<mod_by_zero>" |
QSV_INVALID_RESOURCE |
undefined | "<invalid_resource>" |
QSV_CANNOT_EXECUTE |
undefined | "<cannot_execute>" |
QSV_CANNOT_UNWRAP |
undefined | "<cannot_unwrap>" |
QSV_SCOPE_LITERAL |
string | "literal" |
QSV_SCOPE_RLINK |
string | "rlink" |
QSV_SCOPE_BLOCK |
string | "block" |
QSV_SCOPE_PROPERTY |
string | "property" |
QSV_SCOPE_UNKNOWN |
string | "unknown" |
QSV_UNDEFINED |
undefined | "<undefined>" |
QSV_INVALID_VALUE |
undefined | "<invalid_value>" |
QSV_NO_OBJECT |
undefined | "<no_object>" |
QSV_ALREADY_WOUND |
undefined | "<already_wound>" |
QSV_INVALID_PROPERTY |
undefined | "<invalid_property>" |
scheme:
world:
resource:
object:
rlink:
rlink chain:
priority:
injecting:
ejecting:
winding:
unwinding:
rewinding:
influence:
value:
action: