mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
Preprend every definition line type with a colon, remove function decorator, add immediately ran definition line
This commit is contained in:
parent
7b756ad092
commit
d1f49d1894
117 changed files with 686 additions and 658 deletions
361
LANGUAGE.md
361
LANGUAGE.md
|
|
@ -26,7 +26,7 @@ When executing a piece of Anselme code, your scripts will not directly modify th
|
|||
Right after reaching a checkpoint line, Anselme will merge the local state with the global one, i.e., make every change accessible to other scripts, and get checkpointed changes from other scripts.
|
||||
|
||||
```
|
||||
$ main
|
||||
:$ main
|
||||
:var = 5
|
||||
|
||||
~ var := 2
|
||||
|
|
@ -35,14 +35,14 @@ $ main
|
|||
|
||||
(But if we run the script "parallel" in parallel at this point, it will still think var==5)
|
||||
|
||||
§ foo
|
||||
:! foo
|
||||
But the variable will be merged with the global state on a checkpoint
|
||||
|
||||
after: {var}==2, still, as expected
|
||||
|
||||
(And if we run the script "parallel" in parallel at this point, it will now think var==2)
|
||||
|
||||
$ parallel
|
||||
:$ parallel
|
||||
parallel: {main.var}
|
||||
|
||||
~ main
|
||||
|
|
@ -62,8 +62,6 @@ State merging also happens after a checkpoint has been manually called or resume
|
|||
|
||||
There's different types of lines, depending on their first character(s) (after indentation).
|
||||
|
||||
#### Lines that can have children:
|
||||
|
||||
* `(`: comment line. Everything following this is ignored. Doesn't even check for children indentation and syntax correctness, so have fun.
|
||||
|
||||
```
|
||||
|
|
@ -74,6 +72,60 @@ There's different types of lines, depending on their first character(s) (after i
|
|||
here
|
||||
```
|
||||
|
||||
#### Text lines:
|
||||
|
||||
Lines that can append data to the event buffer and emit text or choice events.
|
||||
|
||||
* `>`: write a choice into the [event buffer](#event-buffer). Followed by arbitrary text. Support [text interpolation](#text-interpolation); if a text event is created during the text interpolation, it is added to the choice text content instead of the global event buffer. Support [escape codes](#escape-codes). Empty choices are discarded.
|
||||
|
||||
```
|
||||
:$ f
|
||||
Third choice
|
||||
|
||||
> First choice
|
||||
> Second choice
|
||||
> Last choice
|
||||
> {f}
|
||||
```
|
||||
|
||||
If an unescaped `~`, `~?` or `#` appears in the line, the associated operator is applied to the line (see [operators](#operators)), using the previous text as the left argument and everything that follows as the right argument expression.
|
||||
|
||||
```
|
||||
(Conditionnaly executing a line)
|
||||
:$ fn
|
||||
> show this choice only once ~ 👁️
|
||||
|
||||
(Tagging a single line)
|
||||
> tagged # 42
|
||||
not tagged
|
||||
```
|
||||
|
||||
* regular text, i.e. any line that doesn't start with a special line type caracter: write some text into the [event buffer](#event-buffer). Support [text interpolation](#text-interpolation). Support [escape codes](#escape-codes). Don't accept children lines.
|
||||
|
||||
```
|
||||
Hello,
|
||||
this is some text.
|
||||
|
||||
And this is more text, in a different event.
|
||||
```
|
||||
|
||||
If an unescaped `~`, `~?` or `#` appears in the line, the associated operator is applied to the line (see [operators](#operators)), using the previous text as the left argument and everything that follows as the right argument expression.
|
||||
|
||||
```
|
||||
(Conditionnaly executing a line)
|
||||
:$ fn
|
||||
run this line only once ~ 👁️
|
||||
|
||||
(Tagging a single line)
|
||||
tagged # 42
|
||||
```
|
||||
|
||||
* empty line: flush the event buffer, i.e., if there are any pending lines of text or choices, send them to your game. See [Event buffer](#event-buffer). This line always keep the same identation as the last non-empty line, so you don't need to put invisible whitespace on an empty-looking line. Is also automatically added at the end of a file. Don't accept children lines.
|
||||
|
||||
#### Expression lines:
|
||||
|
||||
Lines that evaluate an [expression](#expressions) and do something with the result.
|
||||
|
||||
* `~`: condition line. Can be followed by an [expression](#expressions); otherwise the expression `1` is assumed. If the expression evaluates to [true](#truethness), run its children. Without children, this line is typically use to simply run an expression.
|
||||
|
||||
* `~~`: else-condition. Same as a condition line, but is only run if the last condition or else-condition line (in the same indentation block) was false (regardless of line distance).
|
||||
|
|
@ -111,51 +163,111 @@ There's different types of lines, depending on their first character(s) (after i
|
|||
This is run.
|
||||
```
|
||||
|
||||
* `>`: write a choice into the [event buffer](#event-buffer). Followed by arbitrary text. Support [text interpolation](#text-interpolation); if a text event is created during the text interpolation, it is added to the choice text content instead of the global event buffer. Support [escape codes](#escape-codes). Empty choices are discarded.
|
||||
* `#`: tag line. Can be followed by an [expression](#expressions); otherwise nil expression is assumed. The results of the [expression](#expressions) will be wrapped in a map and added to the tags send along with any `choice` or `text` event sent from its children. Can be nested.
|
||||
|
||||
```
|
||||
$ f
|
||||
Third choice
|
||||
# color="red"
|
||||
Text tagged with a red color
|
||||
|
||||
> First choice
|
||||
> Second choice
|
||||
> Last choice
|
||||
> {f}
|
||||
# "blink"
|
||||
Tagged with a red color and blink.
|
||||
```
|
||||
|
||||
If an unescaped `~`, `~?` or `#` appears in the line, the associated operator is applied to the line (see [operators](#operators)), using the previous text as the left argument and everything that follows as the right argument expression.
|
||||
* `@`: return line. Can be followed by an [expression](#expressions); otherwise nil expression is assumed. Exit the current function and returns the expression's value.
|
||||
|
||||
```
|
||||
(Conditionnaly executing a line)
|
||||
$ fn
|
||||
> show this choice only once ~ 👁️
|
||||
:$ hey
|
||||
@5
|
||||
|
||||
(Tagging a single line)
|
||||
> tagged # 42
|
||||
not tagged
|
||||
{hey} = 5
|
||||
```
|
||||
|
||||
* `$`: function line. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases), and eventually a parameter list. Define a function using its children as function body. Also define a new namespace for its children (using the function name if it has no arguments, or a unique name otherwise).
|
||||
If this line has children, they will be ran _after_ evaluating the returned expression but _before_ exiting the current function. If the children return a value, it is used instead.
|
||||
|
||||
```
|
||||
(Returns 0 and print 5)
|
||||
:$ fn
|
||||
:i=0
|
||||
|
||||
@i
|
||||
~ i:=5
|
||||
{i}
|
||||
|
||||
(Returns 3)
|
||||
:$ g
|
||||
@0
|
||||
@3
|
||||
```
|
||||
|
||||
Please note that Anselme will discard returns values sent from within a choice block. Returns inside choice block still have the expected behaviour of stopping the execution of the choice block.
|
||||
|
||||
This is the case because choice blocks are not ran right as they are read, but only at the next event flush (i.e. empty line). This means that if there is no flush in the function itself, the choice will be ran *after* the function has already been executed and returning a value at this point makes no sense:
|
||||
|
||||
```
|
||||
:$ f
|
||||
> a
|
||||
@1
|
||||
@2
|
||||
|
||||
(f will return 2 since the choice is run after the @2 line)
|
||||
~ f == 2
|
||||
|
||||
Yes.
|
||||
|
||||
(Choice block is actually ran right before the "Yes" line, when the choice event is flushed.)
|
||||
```
|
||||
|
||||
#### Definition lines:
|
||||
|
||||
Definition lines are used to define variables, constants, functions, checkpoints, and objects. Definition lines always start with `:`.
|
||||
|
||||
For every definition line type, it is possible to make it so it is immediately ran after definition by inserting a `~` after the initial `:`:
|
||||
|
||||
```
|
||||
:~ var = &fn
|
||||
|
||||
:~$ loop
|
||||
This text is run immediately.
|
||||
> Loop
|
||||
@loop
|
||||
> Exit
|
||||
```
|
||||
|
||||
is equivalent to
|
||||
|
||||
```
|
||||
:var = &fn
|
||||
~ var
|
||||
|
||||
:$ loop
|
||||
This text is run immediately.
|
||||
> Loop
|
||||
@loop
|
||||
> Exit
|
||||
~ loop
|
||||
```
|
||||
|
||||
* `:$`: function definition line. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases), and eventually a parameter list. Define a function using its children as function body. Also define a new namespace for its children (using the function name if it has no arguments, or a unique name otherwise).
|
||||
|
||||
The function body is not executed when the line is reached; it must be explicitely called in an expression. See [expressions](#function-calls) to see the different ways of calling a function.
|
||||
|
||||
A parameter list can be optionally given after the identifier. Parameter names are identifiers, with eventually an alias (after a `:`) and a default value (after a `=`), and then a type constraint (after a `::`). It is enclosed with paranthesis and contain a comma-separated list of identifiers:
|
||||
|
||||
```
|
||||
$ f(a, b: alias for b, c="default for c", d: alias for d = "default for d")
|
||||
:$ f(a, b: alias for b, c="default for c", d: alias for d = "default for d")
|
||||
first argument: {a}
|
||||
second argument: {b}
|
||||
third argument: {c}
|
||||
fourth argument: {d}
|
||||
|
||||
$ f(a::string, b: alias for b::string, c::alias="default for c"::string)
|
||||
:$ f(a::string, b: alias for b::string, c::alias="default for c"::string)
|
||||
same
|
||||
```
|
||||
|
||||
Functions can also have a variable number of arguments. By adding `...` after the last argument identifier, it will be considered a variable length argument ("vararg"), and will contain a list of every extraneous argument.
|
||||
|
||||
```
|
||||
$ f(a, b...)
|
||||
:$ f(a, b...)
|
||||
{b}
|
||||
|
||||
(will print [1])
|
||||
|
|
@ -172,7 +284,7 @@ When a parameter list is given (or just empty parentheses `()`), the function is
|
|||
|
||||
```
|
||||
(Non-scoped function: usual behaviour, variables are accessible from everywhere and always.)
|
||||
$ f
|
||||
:$ f
|
||||
:a = 1
|
||||
~ a += 1
|
||||
|
||||
|
|
@ -182,7 +294,7 @@ $ f
|
|||
{f.a} is 2
|
||||
|
||||
(Scoped function: can't access g.a from outside the function)
|
||||
$ g()
|
||||
:$ g()
|
||||
:a = 1
|
||||
{a}
|
||||
~ a += 1
|
||||
|
|
@ -198,13 +310,13 @@ This is basically the behaviour you'd expect from functions in most other progra
|
|||
Functions with the same name can be defined, as long as they have a different arguments. Functions will be selected based on the number of arguments given, their name and their type constraint:
|
||||
|
||||
```
|
||||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
a
|
||||
|
||||
$ f(x)
|
||||
:$ f(x)
|
||||
b
|
||||
|
||||
$ f(x::string)
|
||||
:$ f(x::string)
|
||||
c
|
||||
|
||||
(will print a)
|
||||
|
|
@ -223,7 +335,7 @@ Every operator, except assignement operators, `|`, `&`, `,`, `~?`, `~` and `#` c
|
|||
(binary operator names: _op_)
|
||||
(prefix unary operator: op_)
|
||||
(suffix unary operator: _op)
|
||||
$ _/_(a::string, b::string)
|
||||
:$ _/_(a::string, b::string)
|
||||
@"{a}/{b}"
|
||||
```
|
||||
|
||||
|
|
@ -231,9 +343,9 @@ After the parameter list, you may also write `:=` followed by an identifier, and
|
|||
|
||||
```
|
||||
:x = "value"
|
||||
$ f()
|
||||
:$ f()
|
||||
@x
|
||||
$ f() := v
|
||||
:$ f() := v
|
||||
@x := v
|
||||
|
||||
value = {f}
|
||||
|
|
@ -250,7 +362,7 @@ Functions always have the following variables defined in its namespace by defaul
|
|||
`👁️`: number, number of times the function was executed before
|
||||
`🔖`: function reference, last reached checkpoint. `nil` if no checkpoint reached.
|
||||
|
||||
* `§`: checkpoint. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases). Define a checkpoint. Also define a new namespace for its children.
|
||||
* `:!`: checkpoint definition. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases). Define a checkpoint. Also define a new namespace for its children.
|
||||
|
||||
Checkpoints share most of their behavior with functions, with several exceptions. Like functions, the body is not executed when the line is reached; it must either be explicitely called in an expression or executed when resuming the parent function (see checkpoint behaviour below). Can be called in an expression. See [expressions](#checkpoint-calls) to see the different ways of calling a checkpoint manually.
|
||||
|
||||
|
|
@ -259,9 +371,9 @@ The local interpreter state will be merged with the global state when the line i
|
|||
When executing the parent function after this checkpoint has been reached (using the paranthesis-less function call syntax), the function will resume from this checkpoint, and the checkpoint's children will be run. This is meant to be used as a way to restart the conversation from this point after it was interrupted, providing necessary context.
|
||||
|
||||
```
|
||||
$ inane dialog
|
||||
:$ inane dialog
|
||||
Hello George. Nice weather we're having today?
|
||||
§ interrupted
|
||||
:! interrupted
|
||||
What was I saying? Ah yes, the weather...
|
||||
(further dialog here)
|
||||
```
|
||||
|
|
@ -271,14 +383,14 @@ Checkpoints always have the following variable defined in its namespace by defau
|
|||
`👁️`: number, number of times the checkpoint was executed before
|
||||
`🏁`: number, number of times the checkpoint was reached before (includes times where it was resumed from and executed)
|
||||
|
||||
* `%`: class. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases). Define a class. Also define a new namespace for its children.
|
||||
* `:%`: class definition. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases). Define a class. Also define a new namespace for its children.
|
||||
|
||||
Classes share most of their behavior with functions, with a few exceptions. Classes can not take arguments or be scoped; and when called, if the function does not return a value or returns `()` (nil), it will returns a new object instead based on this class. The object can be used to access variables ("attributes") defined in the class, but if one of these attributes is modified on the object it will not change the value in the base class but only in the object.
|
||||
|
||||
Objects can therefore be used to create independant data structures that can contain any variable defined in the base class, inspired by object-oriented programming.
|
||||
|
||||
```
|
||||
% class
|
||||
:% class
|
||||
:a = 1
|
||||
|
||||
:object = class
|
||||
|
|
@ -292,10 +404,10 @@ Is 1: {class.a}
|
|||
Note that the new object returned by the class is also automatically given an annotation that is a reference to the class. This can be used to define methods/function that operate only on objects based on this specific class.
|
||||
|
||||
```
|
||||
% class
|
||||
:% class
|
||||
:a = 1
|
||||
|
||||
$ show(object::&class)
|
||||
:$ show(object::&class)
|
||||
a = {object.a}
|
||||
|
||||
:object = class
|
||||
|
|
@ -303,136 +415,19 @@ $ show(object::&class)
|
|||
~ object!show
|
||||
```
|
||||
|
||||
* `#`: tag line. Can be followed by an [expression](#expressions); otherwise nil expression is assumed. The results of the [expression](#expressions) will be wrapped in a map and added to the tags send along with any `choice` or `text` event sent from its children. Can be nested.
|
||||
|
||||
```
|
||||
# color="red"
|
||||
Text tagged with a red color
|
||||
|
||||
# "blink"
|
||||
Tagged with a red color and blink.
|
||||
```
|
||||
|
||||
* `@`: return line. Can be followed by an [expression](#expressions); otherwise nil expression is assumed. Exit the current function and returns the expression's value.
|
||||
|
||||
```
|
||||
$ hey
|
||||
@5
|
||||
|
||||
{hey} = 5
|
||||
```
|
||||
|
||||
If this line has children, they will be ran _after_ evaluating the returned expression but _before_ exiting the current function. If the children return a value, it is used instead.
|
||||
|
||||
```
|
||||
(Returns 0 and print 5)
|
||||
$ fn
|
||||
:i=0
|
||||
|
||||
@i
|
||||
~ i:=5
|
||||
{i}
|
||||
|
||||
(Returns 3)
|
||||
$ g
|
||||
@0
|
||||
@3
|
||||
```
|
||||
|
||||
Please note that Anselme will discard returns values sent from within a choice block. Returns inside choice block still have the expected behaviour of stopping the execution of the choice block.
|
||||
|
||||
This is the case because choice blocks are not ran right as they are read, but only at the next event flush (i.e. empty line). This means that if there is no flush in the function itself, the choice will be ran *after* the function has already been executed and returning a value at this point makes no sense:
|
||||
|
||||
```
|
||||
$ f
|
||||
> a
|
||||
@1
|
||||
@2
|
||||
|
||||
(f will return 2 since the choice is run after the @2 line)
|
||||
~ f == 2
|
||||
|
||||
Yes.
|
||||
|
||||
(Choice block is actually ran right before the "Yes" line, when the choice event is flushed.)
|
||||
```
|
||||
|
||||
#### Lines that can't have children:
|
||||
|
||||
* `:`: variable declaration. Followed by an [identifier](#identifiers) (with eventually an [alias](#aliases)), a `=` and an [expression](#expressions). Defines a variable with a default value and this identifier in the current [namespace]("identifiers"). The expression is not evaluated instantly, but the first time the variable is used.
|
||||
* `:`: variable declaration. Followed by an [identifier](#identifiers) (with eventually an [alias](#aliases)), a `=` and an [expression](#expressions). Defines a variable with a default value and this identifier in the current [namespace]("identifiers"). The expression is not evaluated instantly, but the first time the variable is used. Don't accept children lines.
|
||||
|
||||
```
|
||||
:foo = 42
|
||||
:bar : alias = 12
|
||||
```
|
||||
|
||||
You can also use two colons instead of one to define a constant:
|
||||
* `::`: constant declaration. Work the same way as a variable declaration, but the variable can't be reassigned after their declaration and first evaluation, and their value is marked as constant (i.e. can not be modified even it is of a mutable type). Constants are not stored in save files and should therefore always contain the result of the expression written in the script file, even if the script has been updated.
|
||||
|
||||
```
|
||||
::foo = 42
|
||||
```
|
||||
|
||||
After their declaration and first evaluation, constants cannot be reassigned and their value is marked as constant (i.e. can not be modified even it is of a mutable type). Constants are not stored in save files and should therefore always contain the result of the expression written in the script file, even if the script has been updated.
|
||||
|
||||
* empty line: flush the event buffer, i.e., if there are any pending lines of text or choices, send them to your game. See [Event buffer](#event-buffer). This line always keep the same identation as the last non-empty line, so you don't need to put invisible whitespace on an empty-looking line. Is also automatically added at the end of a file.
|
||||
|
||||
* regular text: write some text into the [event buffer](#event-buffer). Support [text interpolation](#text-interpolation). Support [escape codes](#escape-codes).
|
||||
|
||||
```
|
||||
Hello,
|
||||
this is some text.
|
||||
|
||||
And this is more text, in a different event.
|
||||
```
|
||||
|
||||
If an unescaped `~`, `~?` or `#` appears in the line, the associated operator is applied to the line (see [operators](#operators)), using the previous text as the left argument and everything that follows as the right argument expression.
|
||||
|
||||
```
|
||||
(Conditionnaly executing a line)
|
||||
$ fn
|
||||
run this line only once ~ 👁️
|
||||
|
||||
(Tagging a single line)
|
||||
tagged # 42
|
||||
```
|
||||
|
||||
### Line decorators
|
||||
|
||||
Every line can also be followed with decorators, which are appended at the end of the line and affect its behaviour. Decorators are just syntaxic sugar to make some common operations simpler to write.
|
||||
|
||||
* `$`: function decorator. Same as a function line, behaving as if this line was it sole child, but also run the function. Function can not take arguments.
|
||||
|
||||
```
|
||||
text $ f
|
||||
```
|
||||
|
||||
is equivalent to:
|
||||
|
||||
```
|
||||
~ f
|
||||
$ f
|
||||
text
|
||||
```
|
||||
|
||||
This is typically used for immediatletly running functions when defining them, for example for a looping choice :
|
||||
|
||||
```
|
||||
~$ loop
|
||||
> Loop
|
||||
@loop
|
||||
> Exit
|
||||
```
|
||||
|
||||
is equivalent to:
|
||||
|
||||
```
|
||||
$ loop
|
||||
> Loop
|
||||
@loop
|
||||
> Exit
|
||||
~ loop
|
||||
```
|
||||
|
||||
### Text interpolation
|
||||
|
||||
Text and choice lines allow for arbitrary text. Expression can be evaluated and inserted into the text as the line is executed by enclosing the [expression](#expressions) into brackets. The expressions are evaluated in the same order as the reading direction.
|
||||
|
|
@ -449,7 +444,7 @@ Text interpolated in choices have the special property of capturing text events
|
|||
Value of a: {a}
|
||||
|
||||
(in text and choices, text events created from an interpolated expression are included in the final text)
|
||||
$ f
|
||||
:$ f
|
||||
wor
|
||||
(the returned value comes after)
|
||||
@"ld."
|
||||
|
|
@ -510,7 +505,7 @@ Beyond technical reasons, the event buffer serves as a way to group together sev
|
|||
In practise, this is mostly useful to provide some choice or text from another function:
|
||||
|
||||
```
|
||||
$ reusable choice
|
||||
:$ reusable choice
|
||||
> Reusable choice
|
||||
|
||||
> Choice A
|
||||
|
|
@ -538,7 +533,7 @@ Some text # tag
|
|||
|
||||
```
|
||||
(There is a space between the text and the tag expression; but there is a space as well after the text interpolation in the last line. The two spaces are converted into a single space (the space will belong to the first text element, i.e. the "text " element).)
|
||||
$ f
|
||||
:$ f
|
||||
text # tag
|
||||
|
||||
Some {text} here.
|
||||
|
|
@ -555,9 +550,9 @@ When defining an identifier (using a function, checkpoint or variable delcaratio
|
|||
In practise, this means you have to use the "genealogy" of the variable to refer to it from a line not in the same namespace:
|
||||
|
||||
```
|
||||
$ fn1
|
||||
:$ fn1
|
||||
(everything here is in the fn1 namespace)
|
||||
$ fn2
|
||||
:$ fn2
|
||||
(fn1.fn2 namespace)
|
||||
:var2 = 42
|
||||
Var2 = 42: {var2}
|
||||
|
|
@ -749,14 +744,14 @@ When the identifier is preceeded by another expression directly (without any ope
|
|||
The simplest way to call a function is simply to use its name. If the function has no arguments, parantheses are optional, or can be replaced with a `!`:
|
||||
|
||||
```
|
||||
$ f
|
||||
:$ f
|
||||
called
|
||||
|
||||
~ f
|
||||
(equivalent to)
|
||||
~ f!
|
||||
|
||||
$ f(a)
|
||||
:$ f(a)
|
||||
called with {a}
|
||||
|
||||
~ f("an argument")
|
||||
|
|
@ -765,9 +760,9 @@ $ f(a)
|
|||
Please note, however, that if the function contains checkpoints, these two syntaxes behave differently. Without parantheses, the function will resume from the last reached checkpoint; with parantheses, the function always restart from its beginning:
|
||||
|
||||
```
|
||||
$ f
|
||||
:$ f
|
||||
a
|
||||
§ checkpoint
|
||||
:! checkpoint
|
||||
b
|
||||
c
|
||||
|
||||
|
|
@ -785,12 +780,12 @@ Force no checkpoint, will write "a" and "c":
|
|||
Functions with arguments can also be called with a "method-like" syntax using the `!` operator (though Anselme has no concept of classes and methods):
|
||||
|
||||
```
|
||||
$ f(a)
|
||||
:$ f(a)
|
||||
called with {a}
|
||||
|
||||
"an argument"!f
|
||||
|
||||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
called with {a} and {b}
|
||||
|
||||
"an argument"!f("another argument")
|
||||
|
|
@ -799,7 +794,7 @@ $ f(a, b)
|
|||
If the function has a return value, any of these calls will of course return the value.
|
||||
|
||||
```
|
||||
$ f
|
||||
:$ f
|
||||
@"text"
|
||||
|
||||
this is text: {f}
|
||||
|
|
@ -808,12 +803,12 @@ this is text: {f}
|
|||
Functions can also have default arguments. Defaults values can be any expression and are re-evaluated each time the function is called:
|
||||
|
||||
```
|
||||
$ f(a, b=1)
|
||||
:$ f(a, b=1)
|
||||
@a+b
|
||||
|
||||
{f(1)} = 2
|
||||
|
||||
$ g(a, b=a)
|
||||
:$ g(a, b=a)
|
||||
@a+b
|
||||
|
||||
{g(1)} = 2
|
||||
|
|
@ -823,7 +818,7 @@ $ g(a, b=a)
|
|||
Arguments can also be passed by naming them instead of their position. These syntaxes can be mixed:
|
||||
|
||||
```
|
||||
$ f(a, b, c)
|
||||
:$ f(a, b, c)
|
||||
@a + b + c
|
||||
|
||||
{f(1,2,3)} = {f(c=3,b=2,a=1)} = {f(1,2,c=3)}
|
||||
|
|
@ -836,7 +831,7 @@ This means that pairs can't be passed directly as arguments to a function (as th
|
|||
Functions can have a variable number of arguments. Additional arguments are added in a list:
|
||||
|
||||
```
|
||||
$ f(a, b...)
|
||||
:$ f(a, b...)
|
||||
{a}
|
||||
|
||||
{b}
|
||||
|
|
@ -851,16 +846,16 @@ $ f(a, b...)
|
|||
Anselme use dynamic dispatch, meaning the correct function is selected at runtime. The correct function is selected based on number of arguments, argument names, and argument type constraint. The function with the most specific arguments will be selected. If several functions match, an error is thrown.
|
||||
|
||||
```
|
||||
$ fn(x::number, y)
|
||||
:$ fn(x::number, y)
|
||||
a
|
||||
|
||||
$ fn(x::number)
|
||||
:$ fn(x::number)
|
||||
b
|
||||
|
||||
$ fn(a::string)
|
||||
:$ fn(a::string)
|
||||
c
|
||||
|
||||
$ fn(x::number, y::number)
|
||||
:$ fn(x::number, y::number)
|
||||
c
|
||||
|
||||
a = {fn(5, "s")}
|
||||
|
|
@ -871,9 +866,9 @@ c = {fn(5)}
|
|||
|
||||
d = {fn(5, 2)}
|
||||
|
||||
$ g(x)
|
||||
:$ g(x)
|
||||
|
||||
$ g(x, a="t")
|
||||
:$ g(x, a="t")
|
||||
|
||||
error, can't select unique function: {g(5)}
|
||||
```
|
||||
|
|
@ -887,9 +882,9 @@ Most of the time, you should'nt need to call checkpoints yourself - they will be
|
|||
But in the cases when you want to manually set the current checkpoint, you can call it with a similar syntax to paranthesis-less function calls:
|
||||
|
||||
```
|
||||
$ f
|
||||
:$ f
|
||||
a
|
||||
§ checkpoint
|
||||
:! checkpoint
|
||||
b
|
||||
c
|
||||
|
||||
|
|
@ -907,9 +902,9 @@ Function can always be restarted from the begining using parantheses:
|
|||
You can also only execute the checkpoints' children code only by using a parantheses-syntax:
|
||||
|
||||
```
|
||||
$ f
|
||||
:$ f
|
||||
a
|
||||
§ checkpoint
|
||||
:! checkpoint
|
||||
b
|
||||
c
|
||||
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ local vm_mt = {
|
|||
else
|
||||
if type(fn) == "function" then fn = { value = fn } end
|
||||
self.state.link_next_function_definition_to_lua_function = fn
|
||||
local s, e = self:loadstring("$"..signature, "", "lua")
|
||||
local s, e = self:loadstring(":$"..signature, "", "lua")
|
||||
if not s then return nil, e end
|
||||
assert(self.state.link_next_function_definition_to_lua_function == nil, "unexpected error while defining lua function")
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ TODO: type system is not super nice to use.
|
|||
TODO: some sensible way to capture text event in string litterals (string interpolation/subtexts)? -> meh, this means we can capture choice events, and choice events contain their code block, and we don't want to store code blocks in the save file (as code can be updated/translated/whatever)
|
||||
ignoring choice events, we might be able to use subtexts in string litterals; using the same code for text lines and text litterals? we would lose tags...
|
||||
|
||||
TODO: the function decorator feels a bit glued-on to the current syntax
|
||||
|
||||
TODO: simplify language, it is much too complicated. Less line types? (var def, func, checkpoint, tag). Rewrite some ad hoc syntax using the expression system?
|
||||
|
||||
TODO: fn/checkpoint/tag: maybe consider them a regular func call that takes children as arg; can keep compatibility using $/§ as shortcut for the actual call.
|
||||
|
|
|
|||
|
|
@ -62,15 +62,15 @@ local function parse(state)
|
|||
line.expression = exp
|
||||
-- variable pending definition: expression will be evaluated when variable is needed
|
||||
if line.type == "definition" then
|
||||
state.variables[line.fqm].value.expression = line.expression
|
||||
state.variables[line.name].value.expression = line.expression
|
||||
-- parse constraints
|
||||
if line.constraint then
|
||||
local type_exp, rem2 = expression(line.constraint, state, namespace)
|
||||
if not type_exp then return nil, ("in type constraint, %s; at %s"):format(rem2, line.source) end
|
||||
if rem2:match("[^%s]") then
|
||||
return nil, ("unexpected characters after variable %q: %q; at %s"):format(line.fqm, rem2, line.source)
|
||||
return nil, ("unexpected characters after variable %q: %q; at %s"):format(line.name, rem2, line.source)
|
||||
end
|
||||
state.variable_constraints[line.fqm] = { pending = type_exp }
|
||||
state.variable_constraints[line.name] = { pending = type_exp }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,77 +53,112 @@ local function parse_line(line, state, namespace, parent_function)
|
|||
r.type = "choice"
|
||||
r.child = true
|
||||
r.text = l:match("^>%s*(.-)$")
|
||||
-- function & checkpoint
|
||||
elseif l:match("^%$") or l:match("^§") or l:match("^%%") then -- § is a 2-bytes caracter, DO NOT USE LUA PATTERN OPERATORS as they operate on single bytes
|
||||
r.type = "function"
|
||||
r.child = true
|
||||
-- subtype options
|
||||
local allow_params = true
|
||||
local allow_assign = true
|
||||
local keep_in_ast = false
|
||||
if l:match("^%$") then
|
||||
r.subtype = "function"
|
||||
r.resume_boundary = true
|
||||
elseif l:match("^%%") then
|
||||
r.subtype = "class"
|
||||
r.resume_boundary = true
|
||||
allow_params = false
|
||||
allow_assign = false
|
||||
elseif l:match("^§") then
|
||||
r.subtype = "checkpoint"
|
||||
allow_params = false
|
||||
allow_assign = false
|
||||
keep_in_ast = true
|
||||
r.parent_function = parent_function -- store parent function and run checkpoint when line is read
|
||||
else
|
||||
error("unknown function line type")
|
||||
-- definition
|
||||
elseif l:match("^:") then
|
||||
local lr = l:match("^:(.*)$")
|
||||
-- immediately run variable
|
||||
local run_immediately = false
|
||||
if lr:match("^~") then
|
||||
lr = lr:match("^~(.*)$")
|
||||
run_immediately = true
|
||||
end
|
||||
-- don't keep function node in block AST
|
||||
if not keep_in_ast then
|
||||
r.remove_from_block_ast = true
|
||||
end
|
||||
-- lua function
|
||||
if r.subtype == "function" and state.global_state.link_next_function_definition_to_lua_function then
|
||||
r.lua_function = state.global_state.link_next_function_definition_to_lua_function
|
||||
state.global_state.link_next_function_definition_to_lua_function = nil
|
||||
end
|
||||
-- get identifier
|
||||
local lc = l:match("^[%$%%](.-)$") or l:match("^§(.-)$")
|
||||
local identifier, rem = lc:match("^("..identifier_pattern..")(.-)$")
|
||||
if not identifier then
|
||||
for _, name in ipairs(special_functions_names) do
|
||||
identifier, rem = lc:match("^(%s*"..escape(name).."%s*)(.-)$")
|
||||
if identifier then break end
|
||||
-- function & checkpoint
|
||||
if lr:match("^%$") or lr:match("^%!") or lr:match("^%%") then -- § is a 2-bytes caracter, DO NOT USE LUA PATTERN OPERATORS as they operate on single bytes
|
||||
r.type = "function"
|
||||
r.child = true
|
||||
-- subtype options
|
||||
local allow_params = true
|
||||
local allow_assign = true
|
||||
local keep_in_ast = false
|
||||
if lr:match("^%$") then
|
||||
r.subtype = "function"
|
||||
r.resume_boundary = true
|
||||
elseif lr:match("^%%") then
|
||||
r.subtype = "class"
|
||||
r.resume_boundary = true
|
||||
allow_params = false
|
||||
allow_assign = false
|
||||
elseif lr:match("^%!") then
|
||||
r.subtype = "checkpoint"
|
||||
allow_params = false
|
||||
allow_assign = false
|
||||
keep_in_ast = true
|
||||
r.parent_function = parent_function -- store parent function and run checkpoint when line is read
|
||||
else
|
||||
error("unknown function line type")
|
||||
end
|
||||
end
|
||||
if not identifier then
|
||||
return nil, ("no valid identifier in function definition line %q; at %s"):format(lc, line.source)
|
||||
end
|
||||
-- format identifier
|
||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||
local func_namespace = fqm .. "."
|
||||
-- get alias
|
||||
local ok_alias
|
||||
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
|
||||
if not ok_alias then return ok_alias, rem end
|
||||
-- anything else are argument, isolate function it its own namespace
|
||||
-- (to not mix its args and variables with the main variant)
|
||||
if rem:match("[^%s]") then
|
||||
func_namespace = ("%s(%s)."):format(fqm, tostring(r))
|
||||
r.private_namespace = true
|
||||
end
|
||||
-- define function
|
||||
if state.variables[fqm] then return nil, ("trying to define %s %s, but a variable with the same name exists; at %s"):format(r.type, fqm, line.source) end
|
||||
r.namespace = func_namespace
|
||||
r.name = fqm
|
||||
-- get params
|
||||
r.params = {}
|
||||
if allow_params and rem:match("^%b()") then
|
||||
r.scoped = true
|
||||
local content
|
||||
content, rem = rem:match("^(%b())%s*(.*)$")
|
||||
content = content:gsub("^%(", ""):gsub("%)$", "")
|
||||
for param in content:gmatch("[^%,]+") do
|
||||
-- don't keep function node in block AST
|
||||
if not keep_in_ast then
|
||||
r.remove_from_block_ast = true
|
||||
end
|
||||
-- lua function
|
||||
if r.subtype == "function" and state.global_state.link_next_function_definition_to_lua_function then
|
||||
r.lua_function = state.global_state.link_next_function_definition_to_lua_function
|
||||
state.global_state.link_next_function_definition_to_lua_function = nil
|
||||
end
|
||||
-- get identifier
|
||||
local lc = lr:match("^[%$%%%!](.-)$")
|
||||
local identifier, rem = lc:match("^("..identifier_pattern..")(.-)$")
|
||||
if not identifier then
|
||||
for _, name in ipairs(special_functions_names) do
|
||||
identifier, rem = lc:match("^(%s*"..escape(name).."%s*)(.-)$")
|
||||
if identifier then break end
|
||||
end
|
||||
end
|
||||
if not identifier then
|
||||
return nil, ("no valid identifier in function definition line %q; at %s"):format(lc, line.source)
|
||||
end
|
||||
-- format identifier
|
||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||
local func_namespace = fqm .. "."
|
||||
-- get alias
|
||||
local ok_alias
|
||||
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
|
||||
if not ok_alias then return ok_alias, rem end
|
||||
-- anything else are argument, isolate function it its own namespace
|
||||
-- (to not mix its args and variables with the main variant)
|
||||
if rem:match("[^%s]") then
|
||||
func_namespace = ("%s(%s)."):format(fqm, tostring(r))
|
||||
r.private_namespace = true
|
||||
end
|
||||
-- define function
|
||||
if state.variables[fqm] then return nil, ("trying to define %s %s, but a variable with the same name exists; at %s"):format(r.type, fqm, line.source) end
|
||||
r.namespace = func_namespace
|
||||
r.name = fqm
|
||||
-- get params
|
||||
r.params = {}
|
||||
if allow_params and rem:match("^%b()") then
|
||||
r.scoped = true
|
||||
local content
|
||||
content, rem = rem:match("^(%b())%s*(.*)$")
|
||||
content = content:gsub("^%(", ""):gsub("%)$", "")
|
||||
for param in content:gmatch("[^%,]+") do
|
||||
-- get identifier
|
||||
local param_identifier, param_rem = param:match("^("..identifier_pattern..")(.-)$")
|
||||
if not param_identifier then return nil, ("no valid identifier in function parameter %q; at %s"):format(param, line.source) end
|
||||
param_identifier = format_identifier(param_identifier)
|
||||
-- format identifier
|
||||
local param_fqm = ("%s%s"):format(func_namespace, param_identifier)
|
||||
-- get alias
|
||||
local ok_param_alias, param_alias
|
||||
ok_param_alias, param_rem, param_alias = maybe_alias(param_rem, param_fqm, func_namespace, line, state)
|
||||
if not ok_param_alias then return ok_param_alias, param_rem end
|
||||
-- get potential type constraints and default value
|
||||
local type_constraint, default
|
||||
if param_rem:match("^::") then
|
||||
type_constraint = param_rem:match("^::(.*)$")
|
||||
elseif param_rem:match("^=") then
|
||||
default = param_rem:match("^=(.*)$")
|
||||
elseif param_rem:match("[^%s]") then
|
||||
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
|
||||
end
|
||||
-- add parameter
|
||||
table.insert(r.params, { name = param_identifier, alias = param_alias, full_name = param_fqm, type_constraint = type_constraint, default = default, vararg = nil })
|
||||
end
|
||||
end
|
||||
-- get assignment param
|
||||
if allow_assign and rem:match("^%:%=") then
|
||||
local param = rem:match("^%:%=(.*)$")
|
||||
-- get identifier
|
||||
local param_identifier, param_rem = param:match("^("..identifier_pattern..")(.-)$")
|
||||
if not param_identifier then return nil, ("no valid identifier in function parameter %q; at %s"):format(param, line.source) end
|
||||
|
|
@ -134,199 +169,178 @@ local function parse_line(line, state, namespace, parent_function)
|
|||
local ok_param_alias, param_alias
|
||||
ok_param_alias, param_rem, param_alias = maybe_alias(param_rem, param_fqm, func_namespace, line, state)
|
||||
if not ok_param_alias then return ok_param_alias, param_rem end
|
||||
-- get potential type constraints and default value
|
||||
local type_constraint, default
|
||||
-- get potential type constraint
|
||||
local type_constraint
|
||||
if param_rem:match("^::") then
|
||||
type_constraint = param_rem:match("^::(.*)$")
|
||||
elseif param_rem:match("^=") then
|
||||
default = param_rem:match("^=(.*)$")
|
||||
elseif param_rem:match("[^%s]") then
|
||||
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
|
||||
end
|
||||
-- add parameter
|
||||
table.insert(r.params, { name = param_identifier, alias = param_alias, full_name = param_fqm, type_constraint = type_constraint, default = default, vararg = nil })
|
||||
r.assignment = { name = param_identifier, alias = param_alias, full_name = param_fqm, type_constraint = type_constraint, default = nil, vararg = nil }
|
||||
elseif rem:match("[^%s]") then
|
||||
return nil, ("expected end-of-line at end of function definition line, but got %q; at %s"):format(rem, line.source)
|
||||
end
|
||||
end
|
||||
-- get assignment param
|
||||
if allow_assign and rem:match("^%:%=") then
|
||||
local param = rem:match("^%:%=(.*)$")
|
||||
-- get identifier
|
||||
local param_identifier, param_rem = param:match("^("..identifier_pattern..")(.-)$")
|
||||
if not param_identifier then return nil, ("no valid identifier in function parameter %q; at %s"):format(param, line.source) end
|
||||
param_identifier = format_identifier(param_identifier)
|
||||
-- format identifier
|
||||
local param_fqm = ("%s%s"):format(func_namespace, param_identifier)
|
||||
-- get alias
|
||||
local ok_param_alias, param_alias
|
||||
ok_param_alias, param_rem, param_alias = maybe_alias(param_rem, param_fqm, func_namespace, line, state)
|
||||
if not ok_param_alias then return ok_param_alias, param_rem end
|
||||
-- get potential type constraint
|
||||
local type_constraint
|
||||
if param_rem:match("^::") then
|
||||
type_constraint = param_rem:match("^::(.*)$")
|
||||
elseif param_rem:match("[^%s]") then
|
||||
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
|
||||
-- calculate arity
|
||||
local minarity, maxarity = #r.params, #r.params
|
||||
for _, param in ipairs(r.params) do -- params with default values
|
||||
if param.default then
|
||||
minarity = minarity - 1
|
||||
end
|
||||
end
|
||||
-- add parameter
|
||||
r.assignment = { name = param_identifier, alias = param_alias, full_name = param_fqm, type_constraint = type_constraint, default = nil, vararg = nil }
|
||||
elseif rem:match("[^%s]") then
|
||||
return nil, ("expected end-of-line at end of function definition line, but got %q; at %s"):format(rem, line.source)
|
||||
end
|
||||
-- calculate arity
|
||||
local minarity, maxarity = #r.params, #r.params
|
||||
for _, param in ipairs(r.params) do -- params with default values
|
||||
if param.default then
|
||||
-- varargs
|
||||
if maxarity > 0 and r.params[maxarity].full_name:match("%.%.%.$") then
|
||||
r.params[maxarity].name = r.params[maxarity].name:match("^(.*)%.%.%.$")
|
||||
r.params[maxarity].full_name = r.params[maxarity].full_name:match("^(.*)%.%.%.$")
|
||||
r.params[maxarity].vararg = true
|
||||
minarity = minarity - 1
|
||||
maxarity = math.huge
|
||||
end
|
||||
end
|
||||
-- varargs
|
||||
if maxarity > 0 and r.params[maxarity].full_name:match("%.%.%.$") then
|
||||
r.params[maxarity].name = r.params[maxarity].name:match("^(.*)%.%.%.$")
|
||||
r.params[maxarity].full_name = r.params[maxarity].full_name:match("^(.*)%.%.%.$")
|
||||
r.params[maxarity].vararg = true
|
||||
minarity = minarity - 1
|
||||
maxarity = math.huge
|
||||
end
|
||||
r.arity = { minarity, maxarity }
|
||||
r.signature = signature(r)
|
||||
r.pretty_signature = pretty_signature(r)
|
||||
-- check for signature conflict with functions with the same fqm
|
||||
if state.functions[fqm] then
|
||||
for _, variant in ipairs(state.functions[fqm]) do
|
||||
if r.signature == variant.signature then
|
||||
return nil, ("trying to define %s %s, but another function with same signature %s exists; at %s"):format(r.type, r.pretty_signature, variant.pretty_signature, line.source)
|
||||
r.arity = { minarity, maxarity }
|
||||
r.signature = signature(r)
|
||||
r.pretty_signature = pretty_signature(r)
|
||||
-- check for signature conflict with functions with the same fqm
|
||||
if state.functions[fqm] then
|
||||
for _, variant in ipairs(state.functions[fqm]) do
|
||||
if r.signature == variant.signature then
|
||||
return nil, ("trying to define %s %s, but another function with same signature %s exists; at %s"):format(r.type, r.pretty_signature, variant.pretty_signature, line.source)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- define variables
|
||||
if not line.children then line.children = {} end
|
||||
-- define 👁️ variable
|
||||
local seen_alias = state.global_state.builtin_aliases["👁️"]
|
||||
if seen_alias then
|
||||
table.insert(line.children, 1, { content = (":👁️:%s=0"):format(seen_alias), source = line.source })
|
||||
else
|
||||
table.insert(line.children, 1, { content = ":👁️=0", source = line.source })
|
||||
end
|
||||
if r.subtype ~= "checkpoint" then
|
||||
-- define 🔖 variable
|
||||
local checkpoint_alias = state.global_state.builtin_aliases["🔖"]
|
||||
if checkpoint_alias then
|
||||
table.insert(line.children, 1, { content = (":🔖:%s=()"):format(checkpoint_alias), source = line.source })
|
||||
-- define variables
|
||||
if not line.children then line.children = {} end
|
||||
-- define 👁️ variable
|
||||
local seen_alias = state.global_state.builtin_aliases["👁️"]
|
||||
if seen_alias then
|
||||
table.insert(line.children, 1, { content = (":👁️:%s=0"):format(seen_alias), source = line.source })
|
||||
else
|
||||
table.insert(line.children, 1, { content = ":🔖=()", source = line.source })
|
||||
table.insert(line.children, 1, { content = ":👁️=0", source = line.source })
|
||||
end
|
||||
-- custom code injection
|
||||
if r.scoped then
|
||||
if state.inject.scoped_function_start then
|
||||
for i, ll in ipairs(state.inject.scoped_function_start) do
|
||||
if r.subtype ~= "checkpoint" then
|
||||
-- define 🔖 variable
|
||||
local checkpoint_alias = state.global_state.builtin_aliases["🔖"]
|
||||
if checkpoint_alias then
|
||||
table.insert(line.children, 1, { content = (":🔖:%s=()"):format(checkpoint_alias), source = line.source })
|
||||
else
|
||||
table.insert(line.children, 1, { content = ":🔖=()", source = line.source })
|
||||
end
|
||||
-- custom code injection
|
||||
if r.scoped then
|
||||
if state.inject.scoped_function_start then
|
||||
for i, ll in ipairs(state.inject.scoped_function_start) do
|
||||
table.insert(line.children, 1+i, copy(ll))
|
||||
end
|
||||
end
|
||||
if state.inject.scoped_function_end then
|
||||
for _, ll in ipairs(state.inject.scoped_function_end) do
|
||||
table.insert(line.children, copy(ll))
|
||||
end
|
||||
end
|
||||
else
|
||||
if state.inject.function_start then
|
||||
for i, ll in ipairs(state.inject.function_start) do
|
||||
table.insert(line.children, 1+i, copy(ll))
|
||||
end
|
||||
end
|
||||
if state.inject.function_end then
|
||||
for _, ll in ipairs(state.inject.function_end) do
|
||||
table.insert(line.children, copy(ll))
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif r.subtype == "checkpoint" then
|
||||
-- define 🏁 variable
|
||||
local reached_alias = state.global_state.builtin_aliases["🏁"]
|
||||
if reached_alias then
|
||||
table.insert(line.children, 1, { content = (":🏁:%s=0"):format(reached_alias), source = line.source })
|
||||
else
|
||||
table.insert(line.children, 1, { content = ":🏁=0", source = line.source })
|
||||
end
|
||||
-- custom code injection
|
||||
if state.inject.checkpoint_start then
|
||||
for i, ll in ipairs(state.inject.checkpoint_start) do
|
||||
table.insert(line.children, 1+i, copy(ll))
|
||||
end
|
||||
end
|
||||
if state.inject.scoped_function_end then
|
||||
for _, ll in ipairs(state.inject.scoped_function_end) do
|
||||
table.insert(line.children, copy(ll))
|
||||
end
|
||||
end
|
||||
else
|
||||
if state.inject.function_start then
|
||||
for i, ll in ipairs(state.inject.function_start) do
|
||||
table.insert(line.children, 1+i, copy(ll))
|
||||
end
|
||||
end
|
||||
if state.inject.function_end then
|
||||
for _, ll in ipairs(state.inject.function_end) do
|
||||
if state.inject.checkpoint_end then
|
||||
for _, ll in ipairs(state.inject.checkpoint_end) do
|
||||
table.insert(line.children, copy(ll))
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif r.subtype == "checkpoint" then
|
||||
-- define 🏁 variable
|
||||
local reached_alias = state.global_state.builtin_aliases["🏁"]
|
||||
if reached_alias then
|
||||
table.insert(line.children, 1, { content = (":🏁:%s=0"):format(reached_alias), source = line.source })
|
||||
else
|
||||
table.insert(line.children, 1, { content = ":🏁=0", source = line.source })
|
||||
end
|
||||
-- custom code injection
|
||||
if state.inject.checkpoint_start then
|
||||
for i, ll in ipairs(state.inject.checkpoint_start) do
|
||||
table.insert(line.children, 1+i, copy(ll))
|
||||
-- define args
|
||||
for _, param in ipairs(r.params) do
|
||||
if not state.variables[param.full_name] then
|
||||
state.variables[param.full_name] = {
|
||||
type = "undefined argument",
|
||||
value = nil
|
||||
}
|
||||
else
|
||||
return nil, ("trying to define parameter %q, but a variable with the same name exists; at %s"):format(param.full_name, line.source)
|
||||
end
|
||||
end
|
||||
if state.inject.checkpoint_end then
|
||||
for _, ll in ipairs(state.inject.checkpoint_end) do
|
||||
table.insert(line.children, copy(ll))
|
||||
if r.assignment then
|
||||
if not state.variables[r.assignment.full_name] then
|
||||
state.variables[r.assignment.full_name] = {
|
||||
type = "undefined argument",
|
||||
value = nil
|
||||
}
|
||||
else
|
||||
return nil, ("trying to define parameter %q, but a variable with the same name exists; at %s"):format(r.assignment.full_name, line.source)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- define args
|
||||
for _, param in ipairs(r.params) do
|
||||
if not state.variables[param.full_name] then
|
||||
state.variables[param.full_name] = {
|
||||
type = "undefined argument",
|
||||
value = nil
|
||||
}
|
||||
-- define new function, no other variant yet
|
||||
if not state.functions[fqm] then
|
||||
state.functions[fqm] = { r }
|
||||
-- overloading
|
||||
else
|
||||
return nil, ("trying to define parameter %q, but a variable with the same name exists; at %s"):format(param.full_name, line.source)
|
||||
table.insert(state.functions[fqm], r)
|
||||
end
|
||||
end
|
||||
if r.assignment then
|
||||
if not state.variables[r.assignment.full_name] then
|
||||
state.variables[r.assignment.full_name] = {
|
||||
type = "undefined argument",
|
||||
value = nil
|
||||
}
|
||||
else
|
||||
return nil, ("trying to define parameter %q, but a variable with the same name exists; at %s"):format(r.assignment.full_name, line.source)
|
||||
end
|
||||
end
|
||||
-- define new function, no other variant yet
|
||||
if not state.functions[fqm] then
|
||||
state.functions[fqm] = { r }
|
||||
-- overloading
|
||||
-- variable and constants
|
||||
else
|
||||
table.insert(state.functions[fqm], r)
|
||||
end
|
||||
-- definition
|
||||
elseif l:match("^:") then
|
||||
r.type = "definition"
|
||||
r.remove_from_block_ast = true
|
||||
local rem = l:match("^:(.*)$")
|
||||
-- check if constant
|
||||
if rem:match("^:") then
|
||||
rem = rem:match("^:(.*)$")
|
||||
r.constant = true
|
||||
end
|
||||
-- get identifier
|
||||
local identifier
|
||||
identifier, rem = rem:match("^("..identifier_pattern..")(.-)$")
|
||||
if not identifier then return nil, ("no valid identifier at start of definition line %q; at %s"):format(l, line.source) end
|
||||
-- format identifier
|
||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||
-- get alias
|
||||
local ok_alias
|
||||
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
|
||||
if not ok_alias then return ok_alias, rem end
|
||||
-- type constraint
|
||||
if rem:match("^::(.-)=") then
|
||||
r.constraint, rem = rem:match("^::%s*(.-)%s*(=.*)$")
|
||||
end
|
||||
-- get expression
|
||||
local exp = rem:match("^=(.*)$")
|
||||
if not exp then return nil, ("expected \"= expression\" after %q in definition line; at %s"):format(rem, line.source) end
|
||||
-- define identifier
|
||||
if state.functions[fqm] then return nil, ("trying to define variable %q, but a function with the same name exists; at %s"):format(fqm, line.source) end
|
||||
if state.variables[fqm] then
|
||||
if state.variables[fqm].type == "pending definition" then
|
||||
return nil, ("trying to define variable %q but it is already defined at %s; at %s"):format(fqm, state.variables[fqm].value.source, line.source)
|
||||
else
|
||||
return nil, ("trying to define variable %q but it is already defined; at %s"):format(fqm, line.source)
|
||||
r.type = "definition"
|
||||
r.remove_from_block_ast = true
|
||||
local rem = lr
|
||||
-- check if constant
|
||||
if rem:match("^:") then
|
||||
rem = rem:match("^:(.*)$")
|
||||
r.constant = true
|
||||
end
|
||||
-- get identifier
|
||||
local identifier
|
||||
identifier, rem = rem:match("^("..identifier_pattern..")(.-)$")
|
||||
if not identifier then return nil, ("no valid identifier at start of definition line %q; at %s"):format(l, line.source) end
|
||||
-- format identifier
|
||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||
-- get alias
|
||||
local ok_alias
|
||||
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
|
||||
if not ok_alias then return ok_alias, rem end
|
||||
-- type constraint
|
||||
if rem:match("^::(.-)=") then
|
||||
r.constraint, rem = rem:match("^::%s*(.-)%s*(=.*)$")
|
||||
end
|
||||
-- get expression
|
||||
local exp = rem:match("^=(.*)$")
|
||||
if not exp then return nil, ("expected \"= expression\" after %q in definition line; at %s"):format(rem, line.source) end
|
||||
-- define identifier
|
||||
if state.functions[fqm] then return nil, ("trying to define variable %q, but a function with the same name exists; at %s"):format(fqm, line.source) end
|
||||
if state.variables[fqm] then
|
||||
if state.variables[fqm].type == "pending definition" then
|
||||
return nil, ("trying to define variable %q but it is already defined at %s; at %s"):format(fqm, state.variables[fqm].value.source, line.source)
|
||||
else
|
||||
return nil, ("trying to define variable %q but it is already defined; at %s"):format(fqm, line.source)
|
||||
end
|
||||
end
|
||||
r.name = fqm
|
||||
r.expression = exp
|
||||
state.variables[fqm] = { type = "pending definition", value = { expression = nil, source = r.source } }
|
||||
if r.constant then state.variable_constants[fqm] = true end
|
||||
end
|
||||
-- add expression line after to perform the immediate execution
|
||||
if run_immediately then
|
||||
line.line_after = { content = "~ "..r.name, source = line.source }
|
||||
end
|
||||
r.fqm = fqm
|
||||
r.expression = exp
|
||||
state.variables[fqm] = { type = "pending definition", value = { expression = nil, source = r.source } }
|
||||
if r.constant then state.variable_constants[fqm] = true end
|
||||
-- tag
|
||||
elseif l:match("^%#") then
|
||||
r.type = "tag"
|
||||
|
|
@ -376,7 +390,7 @@ end
|
|||
-- * nil, err: in case of error
|
||||
local function parse_block(indented, state, namespace, parent_function)
|
||||
local block = { type = "block" }
|
||||
for _, l in ipairs(indented) do
|
||||
for i, l in ipairs(indented) do
|
||||
-- parsable line
|
||||
local ast, err = parse_line(l, state, namespace, parent_function)
|
||||
if err then return nil, err end
|
||||
|
|
@ -403,6 +417,11 @@ local function parse_block(indented, state, namespace, parent_function)
|
|||
ast.child = r
|
||||
end
|
||||
end
|
||||
|
||||
-- insert line after
|
||||
if l.line_after then
|
||||
table.insert(indented, i+1, l.line_after)
|
||||
end
|
||||
end
|
||||
return block
|
||||
end
|
||||
|
|
@ -416,17 +435,7 @@ local function transform_indented(indented)
|
|||
if l.content:match("^%(") then
|
||||
table.remove(indented, i)
|
||||
else
|
||||
-- function decorator
|
||||
if l.content:match("^.-[^\\]%$"..identifier_pattern.."$") then
|
||||
local name
|
||||
l.content, name = l.content:match("^(.-[^\\])%$("..identifier_pattern..")$")
|
||||
indented[i] = { content = "~"..name, source = l.source }
|
||||
table.insert(indented, i+1, { content = "$"..name, source = l.source, children = { l } })
|
||||
i = i + 1 -- $ line should not contain any decorator anymore
|
||||
else
|
||||
i = i + 1 -- only increment when no decorator, as there may be several decorators per line
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
-- indented block
|
||||
if l.children then
|
||||
transform_indented(l.children)
|
||||
|
|
@ -497,7 +506,7 @@ parse_indented = function(s, fnname, source)
|
|||
return nil, ("invalid function name %q"):format(fnname)
|
||||
end
|
||||
indented = {
|
||||
{ content = "$ "..fnname, source = ("%s:%s"):format(source, 0), children = indented },
|
||||
{ content = ":$ "..fnname, source = ("%s:%s"):format(source, 0), children = indented },
|
||||
}
|
||||
end
|
||||
-- transform ast
|
||||
|
|
|
|||
|
|
@ -422,21 +422,21 @@ lua_functions = {
|
|||
}
|
||||
|
||||
local anselme_functions = [[
|
||||
$ random(l...)
|
||||
:$ random(l...)
|
||||
~ l(rand(1, l!len))!
|
||||
|
||||
$ next(l...)
|
||||
:$ next(l...)
|
||||
:j = 0
|
||||
~? j += 1; j < len(l) & l(j).👁️ != 0
|
||||
~ l(j)!
|
||||
|
||||
$ cycle(l...)
|
||||
:$ cycle(l...)
|
||||
:f = l(1)
|
||||
:j = 1
|
||||
~? j += 1; j <= len(l) & !((f := l(j); 1) ~ l(j).👁️ < f.👁️)
|
||||
~ f!
|
||||
|
||||
$ concat(l::list, separator=""::string)
|
||||
:$ concat(l::list, separator=""::string)
|
||||
:r = ""
|
||||
:j = 0
|
||||
~? j += 1; j <= len(l)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(str: foo)
|
||||
:$ f(str: foo)
|
||||
@str + foo
|
||||
|
||||
{f("bi")} = {f(foo="bi")}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
$ _-_(a, b)
|
||||
:$ _-_(a, b)
|
||||
@"generic minus"
|
||||
|
||||
$ _-_(a::string, b::string)
|
||||
:$ _-_(a::string, b::string)
|
||||
@a + " minus " + b
|
||||
|
||||
{2-5}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ f
|
||||
:$ f
|
||||
x
|
||||
§ p
|
||||
:! p
|
||||
a
|
||||
|
||||
§ q
|
||||
:! q
|
||||
b
|
||||
|
||||
c
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
1,2,3: {l}
|
||||
|
||||
§ a
|
||||
:! a
|
||||
|
||||
~ l!insert(4)
|
||||
|
||||
1,2,3,4: {l}
|
||||
|
||||
§ b
|
||||
:! b
|
||||
|
||||
~ l!insert(5)
|
||||
|
||||
|
|
@ -22,5 +22,5 @@
|
|||
|
||||
~ error("cancel merge")
|
||||
|
||||
$ after error
|
||||
:$ after error
|
||||
1,2,3,4: {l}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
2: {l}
|
||||
|
||||
§ a
|
||||
:! a
|
||||
|
||||
~ l := 3
|
||||
|
||||
3: {l}
|
||||
|
||||
§ b
|
||||
:! b
|
||||
|
||||
~ l := 4
|
||||
|
||||
|
|
@ -22,5 +22,5 @@
|
|||
|
||||
~ error("cancel merge")
|
||||
|
||||
$ after error
|
||||
:$ after error
|
||||
3: {l}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
§ p
|
||||
:! p
|
||||
seen!
|
||||
|
||||
Seen: {p.seen}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f
|
||||
:$ f
|
||||
> neol
|
||||
nah
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
> No
|
||||
ko
|
||||
|
||||
$ jump button
|
||||
:$ jump button
|
||||
A # 1
|
||||
> Suprise choice!
|
||||
@"JOIN"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
> No
|
||||
ko
|
||||
|
||||
$ jump button
|
||||
:$ jump button
|
||||
A # 1
|
||||
|
||||
@"SPLIT"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
ko
|
||||
~ choose(1)
|
||||
|
||||
$ jump button
|
||||
:$ jump button
|
||||
A # 1
|
||||
|
||||
> Other
|
||||
|
|
@ -13,6 +13,6 @@ $ jump button
|
|||
ok
|
||||
~ choose(2)
|
||||
|
||||
$ move axis
|
||||
:$ move axis
|
||||
left # 1
|
||||
@" joystick"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f
|
||||
:$ f
|
||||
# 42
|
||||
> a
|
||||
b
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ bar
|
||||
:$ bar
|
||||
:var=5
|
||||
|
||||
~ var := 2
|
||||
|
|
@ -7,14 +7,14 @@ $ bar
|
|||
|
||||
~ run("parallel")
|
||||
|
||||
§ foo
|
||||
:! foo
|
||||
checkpoint
|
||||
|
||||
after: {var}
|
||||
|
||||
~ run("parallel")
|
||||
|
||||
$ parallel
|
||||
:$ parallel
|
||||
parallel: {bar.var}
|
||||
|
||||
~ bar
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f
|
||||
:$ f
|
||||
b
|
||||
|
||||
a {f ~ 5} c
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% obj
|
||||
:% obj
|
||||
::a = 12
|
||||
|
||||
:x = obj()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% obj
|
||||
:% obj
|
||||
:a = 12
|
||||
|
||||
::x = obj()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
:person = "personne"
|
||||
|
||||
$ Person(name, age)
|
||||
:$ Person(name, age)
|
||||
@{name=name, age=age}::person
|
||||
|
||||
:abject = Person("Darmanin", 38)
|
||||
|
||||
{abject}
|
||||
|
||||
$ {}(p::person)
|
||||
:$ {}(p::person)
|
||||
@"Name: {p("name")}\nAge: {p("age")}"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
$ a
|
||||
:$ a
|
||||
|
||||
:a = 2
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
:a = 2
|
||||
|
||||
$ a
|
||||
:$ a
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ f : test
|
||||
:$ f : test
|
||||
@"ok"
|
||||
|
||||
{f} = {test}
|
||||
|
||||
$ g : bis(a)
|
||||
:$ g : bis(a)
|
||||
@a
|
||||
|
||||
{g("ye")} = {bis("ye")}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, l...)
|
||||
:$ f(a, l...)
|
||||
{a}
|
||||
{l}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a)
|
||||
:$ f(a)
|
||||
{a}
|
||||
|
||||
~ f("ok")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
{a}{b}
|
||||
|
||||
~ f("ok")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b, l...)
|
||||
:$ f(a, b, l...)
|
||||
{a}{b}
|
||||
{l}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b, l...)
|
||||
:$ f(a, b, l...)
|
||||
{a}{b}
|
||||
{l}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
{a}{b}
|
||||
|
||||
~ f("o", "k")
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
:a = 5
|
||||
|
||||
$ f(p)
|
||||
:$ f(p)
|
||||
@a
|
||||
|
||||
$ f(p) := v
|
||||
:$ f(p) := v
|
||||
v={v}
|
||||
~ a := v
|
||||
|
||||
$ f(p) := v::string
|
||||
:$ f(p) := v::string
|
||||
v2={v}
|
||||
~ a := p
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
|
||||
$ f(x)
|
||||
:$ f(x)
|
||||
|
||||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
:french name="french"::name
|
||||
:esperanto name="esperanto"::name
|
||||
|
||||
$ a(name::string)
|
||||
:$ a(name::string)
|
||||
{name} is english or generic
|
||||
|
||||
$ a(name:nom::french name)
|
||||
:$ a(name:nom::french name)
|
||||
{nom} is french
|
||||
|
||||
~ a("bob"::name)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
:french name="french"::name
|
||||
:esperanto name="esperanto"::name
|
||||
|
||||
$ a(name)
|
||||
:$ a(name)
|
||||
{name} is english or generic
|
||||
|
||||
$ a(name:nom::french name)
|
||||
:$ a(name:nom::french name)
|
||||
{nom} is french
|
||||
|
||||
~ a("bob"::name)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ f
|
||||
$ a
|
||||
:$ f
|
||||
:$ a
|
||||
a
|
||||
$ b
|
||||
:$ b
|
||||
b
|
||||
$ c
|
||||
:$ c
|
||||
c
|
||||
~ cycle(&a,&b,&c)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
a.👁️: {a.👁️} $ a
|
||||
|
||||
~ a()
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
$ f
|
||||
ko
|
||||
a.👁️: {a.👁️} $ a
|
||||
ok
|
||||
|
||||
~ f.a
|
||||
|
||||
In function:
|
||||
~ f
|
||||
|
|
@ -1 +0,0 @@
|
|||
a.👁️: {a.👁️} $ a
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
$ fn(x)
|
||||
:$ fn(x)
|
||||
x
|
||||
|
||||
$ fn(a)
|
||||
:$ fn(a)
|
||||
a
|
||||
|
||||
~ fn(a=5)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ f
|
||||
$ a
|
||||
:$ f
|
||||
:$ a
|
||||
a
|
||||
$ b
|
||||
:$ b
|
||||
b
|
||||
$ c
|
||||
:$ c
|
||||
c
|
||||
~ next(&a, &b, &c)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
|
||||
$ f(x)
|
||||
:$ f(x)
|
||||
|
||||
$ f(u, v)
|
||||
:$ f(u, v)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ f
|
||||
$ a
|
||||
:$ f
|
||||
:$ a
|
||||
a
|
||||
$ b
|
||||
:$ b
|
||||
b
|
||||
$ c
|
||||
:$ c
|
||||
c
|
||||
~ random(&a,&b,&c)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
$ fn
|
||||
:$ fn
|
||||
1
|
||||
§ c
|
||||
:! c
|
||||
2
|
||||
|
||||
:c = &fn
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
$ f(x)
|
||||
:$ f(x)
|
||||
@x+2
|
||||
|
||||
$ g(x)
|
||||
:$ g(x)
|
||||
@x+3
|
||||
|
||||
:a = &f
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
$ fn
|
||||
:$ fn
|
||||
@1
|
||||
|
||||
$ add(x)
|
||||
:$ add(x)
|
||||
@x+2
|
||||
|
||||
:c = &fn
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$ f
|
||||
$ a
|
||||
:$ f
|
||||
:$ a
|
||||
@12
|
||||
|
||||
:x = &f
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f
|
||||
:$ f
|
||||
:a = 12
|
||||
|
||||
:x = &f
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$ hey
|
||||
§ foo
|
||||
:$ hey
|
||||
:! foo
|
||||
@2
|
||||
@3
|
||||
@5
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ hey
|
||||
:$ hey
|
||||
@5
|
||||
a
|
||||
@2
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$ hey
|
||||
§ foo
|
||||
:$ hey
|
||||
:! foo
|
||||
@2
|
||||
@5
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ hey
|
||||
:$ hey
|
||||
@5
|
||||
|
||||
{hey}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
$ a
|
||||
:$ a
|
||||
:b = 5
|
||||
|
||||
a: {b}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ a
|
||||
:$ a
|
||||
:b = 5
|
||||
|
||||
a: {a.b}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
:n = 0
|
||||
|
||||
$ f(c=1)
|
||||
:$ f(c=1)
|
||||
:a = []
|
||||
|
||||
start: {a}
|
||||
|
|
@ -20,7 +20,7 @@ new list each time:
|
|||
|
||||
~ f
|
||||
|
||||
$ g(c=1, a=[])
|
||||
:$ g(c=1, a=[])
|
||||
start: {a}
|
||||
|
||||
~ a!insert(c)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
:n = 0
|
||||
|
||||
$ f(c=1)
|
||||
:$ f(c=1)
|
||||
:a = 1
|
||||
|
||||
start: {a}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
$ f()
|
||||
:$ f()
|
||||
:a = 1
|
||||
|
||||
{a}
|
||||
|
||||
~ a := a + 1
|
||||
|
||||
$ g
|
||||
:$ g
|
||||
:a = 1
|
||||
|
||||
{a}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
$ a(x::number)
|
||||
:$ a(x::number)
|
||||
@x + 2
|
||||
|
||||
$ x
|
||||
$ a(x::string)
|
||||
:$ x
|
||||
:$ a(x::string)
|
||||
@x + "heh"
|
||||
|
||||
{a("plop")}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
$ f
|
||||
:$ f
|
||||
:a = 2
|
||||
|
||||
$ f(x)
|
||||
:$ f(x)
|
||||
:a = 5
|
||||
|
||||
$ f(b)
|
||||
:$ f(b)
|
||||
:a = 10
|
||||
|
||||
{f.a} = 2
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
$ fn(x::number)
|
||||
:$ fn(x::number)
|
||||
x
|
||||
|
||||
$ fn(a::number)
|
||||
:$ fn(a::number)
|
||||
a
|
||||
|
||||
~ fn(5)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
$ fn(x::number)
|
||||
:$ fn(x::number)
|
||||
x
|
||||
|
||||
$ fn(a="o"::string)
|
||||
:$ fn(a="o"::string)
|
||||
a
|
||||
|
||||
~ fn("s")
|
||||
|
|
@ -10,10 +10,10 @@ $ fn(a="o"::string)
|
|||
|
||||
~ fn()
|
||||
|
||||
$ g(n="s", a=5::number)
|
||||
:$ g(n="s", a=5::number)
|
||||
@"gn"
|
||||
|
||||
$ g(n="s", a="lol"::string)
|
||||
:$ g(n="s", a="lol"::string)
|
||||
@"gs"
|
||||
|
||||
{g(n="k", a="l")}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
$ fn(x::number)
|
||||
:$ fn(x::number)
|
||||
x
|
||||
|
||||
$ fn(a::string)
|
||||
:$ fn(a::string)
|
||||
a
|
||||
|
||||
~ fn("s")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a)
|
||||
:$ f(a)
|
||||
{a}
|
||||
|
||||
~ "ok"!f
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b)
|
||||
:$ f(a, b)
|
||||
{a}{b}
|
||||
|
||||
~ "o"!f("k")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(l...)
|
||||
:$ f(l...)
|
||||
{l}
|
||||
|
||||
~ f()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(l...)
|
||||
:$ f(l...)
|
||||
{l}
|
||||
|
||||
~ f("o", "k")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f
|
||||
:$ f
|
||||
ok
|
||||
|
||||
~ f
|
||||
|
|
|
|||
4
test/tests/immediately run function explicit call.ans
Normal file
4
test/tests/immediately run function explicit call.ans
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
:~$ a
|
||||
a.👁️: {a.👁️}
|
||||
|
||||
~ a()
|
||||
10
test/tests/immediately run function implicit call.ans
Normal file
10
test/tests/immediately run function implicit call.ans
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
:$ f
|
||||
ko
|
||||
:~$ a
|
||||
a.👁️: {a.👁️}
|
||||
ok
|
||||
|
||||
~ f.a
|
||||
|
||||
In function:
|
||||
~ f
|
||||
2
test/tests/immediately run function scope.ans
Normal file
2
test/tests/immediately run function scope.ans
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
:~$ a
|
||||
a.👁️: {a.👁️}
|
||||
4
test/tests/immediately run variable.ans
Normal file
4
test/tests/immediately run variable.ans
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
:$ a
|
||||
a.👁️: {a.👁️}
|
||||
|
||||
:~ b = &a
|
||||
19
test/tests/immediately run variable.lua
Normal file
19
test/tests/immediately run variable.lua
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
local _={}
|
||||
_[7]={}
|
||||
_[6]={}
|
||||
_[5]={tags=_[7],text="0"}
|
||||
_[4]={tags=_[6],text="a.\240\159\145\129\239\184\143: "}
|
||||
_[3]={_[4],_[5]}
|
||||
_[2]={"return"}
|
||||
_[1]={"text",_[3]}
|
||||
return {_[1],_[2]}
|
||||
--[[
|
||||
{ "text", { {
|
||||
tags = {},
|
||||
text = "a.👁️: "
|
||||
}, {
|
||||
tags = {},
|
||||
text = "0"
|
||||
} } }
|
||||
{ "return" }
|
||||
]]--
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
Function with argument:
|
||||
|
||||
$ f(x)
|
||||
:$ f(x)
|
||||
|
||||
{&f}
|
||||
|
||||
Function without argument:
|
||||
|
||||
$ a
|
||||
:$ a
|
||||
lol
|
||||
$ b
|
||||
:$ b
|
||||
hihi
|
||||
|
||||
a: {a}
|
||||
|
|
@ -39,8 +39,8 @@ ref.b(): {ref.b()}
|
|||
|
||||
Objects:
|
||||
|
||||
% A
|
||||
$ b
|
||||
:% A
|
||||
:$ b
|
||||
KK
|
||||
@1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
$ oh
|
||||
§ leave
|
||||
:$ oh
|
||||
:! leave
|
||||
in interrupt: {bar.var}
|
||||
no
|
||||
$ bar
|
||||
:$ bar
|
||||
:var = 5
|
||||
|
||||
~ var := 2
|
||||
|
|
@ -11,7 +11,7 @@ $ oh
|
|||
|
||||
~ interrupt("leave")
|
||||
|
||||
§ foo
|
||||
:! foo
|
||||
checkpoint
|
||||
|
||||
after: {var}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ leave
|
||||
:$ leave
|
||||
in interrupt: {oh.bar.var}
|
||||
|
||||
$ oh
|
||||
:$ oh
|
||||
no
|
||||
$ bar
|
||||
:$ bar
|
||||
:var = 5
|
||||
|
||||
~ var := 2
|
||||
|
|
@ -12,7 +12,7 @@ $ oh
|
|||
|
||||
~ interrupt("leave")
|
||||
|
||||
§ foo
|
||||
:! foo
|
||||
checkpoint
|
||||
|
||||
after: {var}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
$ bar
|
||||
:$ bar
|
||||
:var = 5
|
||||
|
||||
~ var := 2
|
||||
|
||||
$ leave
|
||||
:$ leave
|
||||
in interrupt: {var}
|
||||
|
||||
before: {var}
|
||||
|
||||
~ interrupt("leave")
|
||||
|
||||
§ foo
|
||||
:! foo
|
||||
checkpoint
|
||||
|
||||
after: {var}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
$ bar
|
||||
:$ bar
|
||||
:var = 5
|
||||
|
||||
~ var := 2
|
||||
|
||||
$ leave
|
||||
:$ leave
|
||||
in interrupt: {var}
|
||||
|
||||
before: {var}
|
||||
|
||||
~ interrupt()
|
||||
|
||||
§ foo
|
||||
:! foo
|
||||
checkpoint
|
||||
|
||||
after: {var}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
$ a
|
||||
:$ a
|
||||
a
|
||||
@1
|
||||
|
||||
$ b
|
||||
:$ b
|
||||
b
|
||||
@0
|
||||
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@ x={x}
|
|||
|
||||
a(x)={a(x)}
|
||||
|
||||
§ ch a
|
||||
:! ch a
|
||||
|
||||
a(x)={a(x)}
|
||||
|
||||
§ ch b
|
||||
:! ch b
|
||||
|
||||
~ x(2) := 3
|
||||
|
||||
a(x)={a(x)}
|
||||
|
||||
§ ch c
|
||||
:! ch c
|
||||
|
||||
a(x)={a(x)}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
~ a!insert(b)
|
||||
|
||||
§ c
|
||||
:! c
|
||||
|
||||
~ b!insert(3)
|
||||
|
||||
§ d
|
||||
:! d
|
||||
|
||||
~ b!insert(4)
|
||||
|
||||
$ check
|
||||
:$ check
|
||||
\[1,\[2,3,4]]: {a}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@
|
|||
|
||||
~ a!insert(b)
|
||||
|
||||
§ c
|
||||
:! c
|
||||
|
||||
~ b!insert(3)
|
||||
|
||||
§ d
|
||||
:! d
|
||||
|
||||
~ b!insert(4)
|
||||
|
||||
~ error("abort")
|
||||
|
||||
$ check
|
||||
:$ check
|
||||
\[1,\[2,3]]: {a}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@
|
|||
|
||||
~ a!insert(b)
|
||||
|
||||
§ c
|
||||
:! c
|
||||
|
||||
~ b!insert(3)
|
||||
|
||||
§ d
|
||||
:! d
|
||||
|
||||
~ a!insert(4)
|
||||
|
||||
~ error("abort")
|
||||
|
||||
$ check
|
||||
:$ check
|
||||
\[1,\[2,3]]: {a}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
~ a!insert(b)
|
||||
|
||||
§ c
|
||||
:! c
|
||||
|
||||
~ b!insert(3)
|
||||
|
||||
§ d
|
||||
:! d
|
||||
|
||||
~ a!insert(4)
|
||||
|
||||
$ check
|
||||
:$ check
|
||||
\[1,\[2,3],4]: {a}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b, c)
|
||||
:$ f(a, b, c)
|
||||
@a + b + c
|
||||
|
||||
{f("a", "b", "c")} = {f(a="a", b="b", c="c")} = {f(c="c", a="a", b="b")}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(l...)
|
||||
:$ f(l...)
|
||||
~ l!len
|
||||
:a = 0
|
||||
~ a := l(1)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% class
|
||||
:% class
|
||||
:a:b = "foo"
|
||||
:c = "bar"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
% class
|
||||
:% class
|
||||
:a:b = "foo"
|
||||
:c = "bar"
|
||||
|
||||
$ new(o::&class, x)
|
||||
:$ new(o::&class, x)
|
||||
~ o.c := x
|
||||
@o
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% class
|
||||
:% class
|
||||
:a:b = "foo"
|
||||
:c = "bar"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% class
|
||||
:% class
|
||||
:a:b = "foo"
|
||||
:c = "bar"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$ f(a, b, c="c")
|
||||
:$ f(a, b, c="c")
|
||||
@a + b + c
|
||||
|
||||
{f("a", "b")} = {f("a", "b", "c")} = {f(b="b", a="a")}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
§ f : test
|
||||
:! f : test
|
||||
@"ok"
|
||||
|
||||
{f} = {test}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
$ f
|
||||
:$ f
|
||||
x
|
||||
§ p
|
||||
:! p
|
||||
a
|
||||
b
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
$ f
|
||||
:$ f
|
||||
x
|
||||
§ p
|
||||
:! p
|
||||
a
|
||||
b
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
$ f
|
||||
:$ f
|
||||
x
|
||||
§ p
|
||||
:! p
|
||||
a
|
||||
b
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
§ p
|
||||
:! p
|
||||
a
|
||||
b
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
$ f
|
||||
:$ f
|
||||
x
|
||||
§ p
|
||||
:! p
|
||||
a
|
||||
|
||||
§ q
|
||||
:! q
|
||||
b
|
||||
|
||||
c
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
$ f
|
||||
:$ f
|
||||
# "a"="a"
|
||||
a
|
||||
~ 1 # "x"="x"
|
||||
# "b"="b"
|
||||
§ p
|
||||
:! p
|
||||
b # "c"="c"
|
||||
|
||||
c
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue