From d1f49d1894487022d146c2674a6873859b503f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Wed, 14 Sep 2022 15:28:58 +0900 Subject: [PATCH] Preprend every definition line type with a colon, remove function decorator, add immediately ran definition line --- LANGUAGE.md | 361 +++++++------ anselme.lua | 2 +- notes.txt | 2 - parser/postparser.lua | 6 +- parser/preparser.lua | 499 +++++++++--------- stdlib/functions.lua | 8 +- test/tests/argument alias.ans | 2 +- test/tests/binary operator overload.ans | 4 +- test/tests/checkpoint change.ans | 6 +- .../checkpoint merging mutable value.ans | 6 +- test/tests/checkpoint merging variable.ans | 6 +- test/tests/checkpoint reached seen.ans | 2 +- test/tests/choice function.ans | 2 +- ...e line interpolation with choice event.ans | 2 +- ...ce line interpolation with event flush.ans | 2 +- ...ice line interpolation with text event.ans | 4 +- test/tests/choice preserve tags.ans | 2 +- test/tests/commit.ans | 6 +- test/tests/condition operator.ans | 2 +- test/tests/constant object attribute.ans | 2 +- test/tests/constant object.ans | 2 +- test/tests/custom text formatting.ans | 4 +- test/tests/define override function.ans | 2 +- test/tests/define override variable.ans | 2 +- test/tests/function alias.ans | 4 +- test/tests/function arg vararg.ans | 2 +- test/tests/function arg.ans | 2 +- test/tests/function args arity check fail.ans | 2 +- test/tests/function args vararg empty.ans | 2 +- test/tests/function args vararg.ans | 2 +- test/tests/function args.ans | 2 +- test/tests/function assignement.ans | 6 +- test/tests/function conflict.ans | 6 +- .../function custom type dispatch error.ans | 4 +- test/tests/function custom type dispatch.ans | 4 +- test/tests/function cycle.ans | 8 +- ...function decorator scope explicit call.ans | 3 - ...function decorator scope implicit call.ans | 9 - test/tests/function decorator scope.ans | 1 - test/tests/function name dispatch.ans | 4 +- test/tests/function next.ans | 8 +- test/tests/function no conflict.ans | 6 +- test/tests/function random.ans | 8 +- .../function reference call explicit call.ans | 4 +- test/tests/function reference call.ans | 4 +- test/tests/function reference chain call.ans | 4 +- ...nction reference dot operator function.ans | 4 +- .../tests/function reference dot operator.ans | 2 +- .../function return exit function nested.ans | 4 +- test/tests/function return exit function.ans | 2 +- test/tests/function return nested.ans | 4 +- test/tests/function return.ans | 2 +- test/tests/function scope wrong.ans | 2 +- test/tests/function scope.ans | 2 +- test/tests/function scoped mutable.ans | 4 +- test/tests/function scoped recursive.ans | 2 +- test/tests/function scoped.ans | 4 +- test/tests/function selection.ans | 6 +- ...nction separate variable from variants.ans | 6 +- .../tests/function type dispatch ambigous.ans | 4 +- .../function type dispatch with default.ans | 8 +- test/tests/function type dispatch.ans | 4 +- test/tests/function ufcs arg.ans | 2 +- test/tests/function ufcs args.ans | 2 +- test/tests/function vararg empty.ans | 2 +- test/tests/function vararg.ans | 2 +- test/tests/function.ans | 2 +- ...immediately run function explicit call.ans | 4 + ...mmediately run function explicit call.lua} | 0 ...immediately run function implicit call.ans | 10 + ...mmediately run function implicit call.lua} | 0 test/tests/immediately run function scope.ans | 2 + ...lua => immediately run function scope.lua} | 0 test/tests/immediately run variable.ans | 4 + test/tests/immediately run variable.lua | 19 + test/tests/implicit call of references.ans | 10 +- .../interrupt callback nested paragraph.ans | 8 +- test/tests/interrupt callback nested.ans | 8 +- test/tests/interrupt callback.ans | 6 +- test/tests/interrupt no callback.ans | 6 +- test/tests/lazy boolean operators.ans | 4 +- test/tests/map index accross checkpoints.ans | 6 +- test/tests/merge nested mutable bis.ans | 6 +- test/tests/merge nested mutable error bis.ans | 6 +- test/tests/merge nested mutable error.ans | 6 +- test/tests/merge nested mutable.ans | 6 +- test/tests/named arguments.ans | 2 +- test/tests/named varag.ans | 2 +- test/tests/object comparaison.ans | 2 +- test/tests/object constructor.ans | 4 +- test/tests/object several.ans | 2 +- test/tests/object simple.ans | 2 +- test/tests/optional arguments.ans | 2 +- test/tests/paragraph alias.ans | 2 +- test/tests/paragraph run force.ans | 4 +- test/tests/paragraph run from.ans | 4 +- test/tests/paragraph run.ans | 4 +- test/tests/paragraph.ans | 2 +- test/tests/resume from nested paragraph.ans | 6 +- .../resume from paragraph restore tags.ans | 4 +- ...sume from paragraph with nested choice.ans | 16 +- ...e from paragraph with nested condition.ans | 8 +- test/tests/return children.ans | 4 +- test/tests/return in choice.ans | 2 +- .../scope checkpoint mutable bis error.ans | 8 +- test/tests/scope checkpoint mutable bis.ans | 6 +- test/tests/scope checkpoint mutable error.ans | 6 +- .../scope checkpoint mutable ter error.ans | 8 +- test/tests/scope checkpoint mutable ter.ans | 6 +- test/tests/scope checkpoint mutable.ans | 4 +- test/tests/subtext.ans | 2 +- test/tests/tag operator.ans | 2 +- ...t line interpolation with choice event.ans | 4 +- ...xt line interpolation with event flush.ans | 4 +- ...ext line interpolation with text event.ans | 4 +- test/tests/unary operator overload.ans | 4 +- test/tests/unseen line.ans | 2 +- 117 files changed, 686 insertions(+), 658 deletions(-) delete mode 100644 test/tests/function decorator scope explicit call.ans delete mode 100644 test/tests/function decorator scope implicit call.ans delete mode 100644 test/tests/function decorator scope.ans create mode 100644 test/tests/immediately run function explicit call.ans rename test/tests/{function decorator scope explicit call.lua => immediately run function explicit call.lua} (100%) create mode 100644 test/tests/immediately run function implicit call.ans rename test/tests/{function decorator scope implicit call.lua => immediately run function implicit call.lua} (100%) create mode 100644 test/tests/immediately run function scope.ans rename test/tests/{function decorator scope.lua => immediately run function scope.lua} (100%) create mode 100644 test/tests/immediately run variable.ans create mode 100644 test/tests/immediately run variable.lua diff --git a/LANGUAGE.md b/LANGUAGE.md index 38227ee..b342ded 100644 --- a/LANGUAGE.md +++ b/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 diff --git a/anselme.lua b/anselme.lua index d5c6473..fc534b6 100644 --- a/anselme.lua +++ b/anselme.lua @@ -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 diff --git a/notes.txt b/notes.txt index e187d8a..f15fb29 100644 --- a/notes.txt +++ b/notes.txt @@ -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. diff --git a/parser/postparser.lua b/parser/postparser.lua index d60bc5b..52dd5a9 100644 --- a/parser/postparser.lua +++ b/parser/postparser.lua @@ -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 diff --git a/parser/preparser.lua b/parser/preparser.lua index 296ace6..4b8cc9e 100644 --- a/parser/preparser.lua +++ b/parser/preparser.lua @@ -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 diff --git a/stdlib/functions.lua b/stdlib/functions.lua index 40d259d..517a43b 100644 --- a/stdlib/functions.lua +++ b/stdlib/functions.lua @@ -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) diff --git a/test/tests/argument alias.ans b/test/tests/argument alias.ans index cebc66b..de6f9a9 100644 --- a/test/tests/argument alias.ans +++ b/test/tests/argument alias.ans @@ -1,4 +1,4 @@ -$ f(str: foo) +:$ f(str: foo) @str + foo {f("bi")} = {f(foo="bi")} diff --git a/test/tests/binary operator overload.ans b/test/tests/binary operator overload.ans index bf8025e..2fe7581 100644 --- a/test/tests/binary operator overload.ans +++ b/test/tests/binary operator overload.ans @@ -1,7 +1,7 @@ -$ _-_(a, b) +:$ _-_(a, b) @"generic minus" -$ _-_(a::string, b::string) +:$ _-_(a::string, b::string) @a + " minus " + b {2-5} diff --git a/test/tests/checkpoint change.ans b/test/tests/checkpoint change.ans index c49bf72..1fdbfe9 100644 --- a/test/tests/checkpoint change.ans +++ b/test/tests/checkpoint change.ans @@ -1,9 +1,9 @@ -$ f +:$ f x - § p + :! p a - § q + :! q b c diff --git a/test/tests/checkpoint merging mutable value.ans b/test/tests/checkpoint merging mutable value.ans index 0d968f4..3a793fc 100644 --- a/test/tests/checkpoint merging mutable value.ans +++ b/test/tests/checkpoint merging mutable value.ans @@ -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} diff --git a/test/tests/checkpoint merging variable.ans b/test/tests/checkpoint merging variable.ans index c2d6136..037fd58 100644 --- a/test/tests/checkpoint merging variable.ans +++ b/test/tests/checkpoint merging variable.ans @@ -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} diff --git a/test/tests/checkpoint reached seen.ans b/test/tests/checkpoint reached seen.ans index b27048c..3619559 100644 --- a/test/tests/checkpoint reached seen.ans +++ b/test/tests/checkpoint reached seen.ans @@ -1,4 +1,4 @@ -§ p +:! p seen! Seen: {p.seen} diff --git a/test/tests/choice function.ans b/test/tests/choice function.ans index b67a78b..e4e3fcc 100644 --- a/test/tests/choice function.ans +++ b/test/tests/choice function.ans @@ -1,4 +1,4 @@ -$ f +:$ f > neol nah diff --git a/test/tests/choice line interpolation with choice event.ans b/test/tests/choice line interpolation with choice event.ans index 834840d..3ba50b9 100644 --- a/test/tests/choice line interpolation with choice event.ans +++ b/test/tests/choice line interpolation with choice event.ans @@ -4,7 +4,7 @@ > No ko -$ jump button +:$ jump button A # 1 > Suprise choice! @"JOIN" diff --git a/test/tests/choice line interpolation with event flush.ans b/test/tests/choice line interpolation with event flush.ans index 6c036fa..bf239c4 100644 --- a/test/tests/choice line interpolation with event flush.ans +++ b/test/tests/choice line interpolation with event flush.ans @@ -5,7 +5,7 @@ > No ko -$ jump button +:$ jump button A # 1 @"SPLIT" diff --git a/test/tests/choice line interpolation with text event.ans b/test/tests/choice line interpolation with text event.ans index d177be0..d149de8 100644 --- a/test/tests/choice line interpolation with text event.ans +++ b/test/tests/choice line interpolation with text event.ans @@ -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" diff --git a/test/tests/choice preserve tags.ans b/test/tests/choice preserve tags.ans index 1df204f..491541a 100644 --- a/test/tests/choice preserve tags.ans +++ b/test/tests/choice preserve tags.ans @@ -1,4 +1,4 @@ -$ f +:$ f # 42 > a b diff --git a/test/tests/commit.ans b/test/tests/commit.ans index 273c158..919fbb3 100644 --- a/test/tests/commit.ans +++ b/test/tests/commit.ans @@ -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 diff --git a/test/tests/condition operator.ans b/test/tests/condition operator.ans index e13469a..7a980bb 100644 --- a/test/tests/condition operator.ans +++ b/test/tests/condition operator.ans @@ -1,4 +1,4 @@ -$ f +:$ f b a {f ~ 5} c diff --git a/test/tests/constant object attribute.ans b/test/tests/constant object attribute.ans index 80659b4..3225098 100644 --- a/test/tests/constant object attribute.ans +++ b/test/tests/constant object attribute.ans @@ -1,4 +1,4 @@ -% obj +:% obj ::a = 12 :x = obj() diff --git a/test/tests/constant object.ans b/test/tests/constant object.ans index 002fa35..4d212b1 100644 --- a/test/tests/constant object.ans +++ b/test/tests/constant object.ans @@ -1,4 +1,4 @@ -% obj +:% obj :a = 12 ::x = obj() diff --git a/test/tests/custom text formatting.ans b/test/tests/custom text formatting.ans index 876231b..9059ab0 100644 --- a/test/tests/custom text formatting.ans +++ b/test/tests/custom text formatting.ans @@ -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")}" diff --git a/test/tests/define override function.ans b/test/tests/define override function.ans index 36ff9c6..79efc81 100644 --- a/test/tests/define override function.ans +++ b/test/tests/define override function.ans @@ -1,3 +1,3 @@ -$ a +:$ a :a = 2 diff --git a/test/tests/define override variable.ans b/test/tests/define override variable.ans index 3a7b80f..0e23022 100644 --- a/test/tests/define override variable.ans +++ b/test/tests/define override variable.ans @@ -1,3 +1,3 @@ :a = 2 -$ a +:$ a diff --git a/test/tests/function alias.ans b/test/tests/function alias.ans index 3148d5f..ab5fa6c 100644 --- a/test/tests/function alias.ans +++ b/test/tests/function alias.ans @@ -1,9 +1,9 @@ -$ f : test +:$ f : test @"ok" {f} = {test} -$ g : bis(a) +:$ g : bis(a) @a {g("ye")} = {bis("ye")} diff --git a/test/tests/function arg vararg.ans b/test/tests/function arg vararg.ans index ee1fc59..72fd74b 100644 --- a/test/tests/function arg vararg.ans +++ b/test/tests/function arg vararg.ans @@ -1,4 +1,4 @@ -$ f(a, l...) +:$ f(a, l...) {a} {l} diff --git a/test/tests/function arg.ans b/test/tests/function arg.ans index ef97053..c102c17 100644 --- a/test/tests/function arg.ans +++ b/test/tests/function arg.ans @@ -1,4 +1,4 @@ -$ f(a) +:$ f(a) {a} ~ f("ok") diff --git a/test/tests/function args arity check fail.ans b/test/tests/function args arity check fail.ans index 8fe5ae6..c41ac2b 100644 --- a/test/tests/function args arity check fail.ans +++ b/test/tests/function args arity check fail.ans @@ -1,4 +1,4 @@ -$ f(a, b) +:$ f(a, b) {a}{b} ~ f("ok") diff --git a/test/tests/function args vararg empty.ans b/test/tests/function args vararg empty.ans index 2fcd1ab..ecdc920 100644 --- a/test/tests/function args vararg empty.ans +++ b/test/tests/function args vararg empty.ans @@ -1,4 +1,4 @@ -$ f(a, b, l...) +:$ f(a, b, l...) {a}{b} {l} diff --git a/test/tests/function args vararg.ans b/test/tests/function args vararg.ans index a321eec..ae02ba7 100644 --- a/test/tests/function args vararg.ans +++ b/test/tests/function args vararg.ans @@ -1,4 +1,4 @@ -$ f(a, b, l...) +:$ f(a, b, l...) {a}{b} {l} diff --git a/test/tests/function args.ans b/test/tests/function args.ans index e260225..736cf22 100644 --- a/test/tests/function args.ans +++ b/test/tests/function args.ans @@ -1,4 +1,4 @@ -$ f(a, b) +:$ f(a, b) {a}{b} ~ f("o", "k") diff --git a/test/tests/function assignement.ans b/test/tests/function assignement.ans index f55ec30..3efecc4 100644 --- a/test/tests/function assignement.ans +++ b/test/tests/function assignement.ans @@ -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 diff --git a/test/tests/function conflict.ans b/test/tests/function conflict.ans index 1a3f8c7..bd9f873 100644 --- a/test/tests/function conflict.ans +++ b/test/tests/function conflict.ans @@ -1,5 +1,5 @@ -$ f(a, b) +:$ f(a, b) -$ f(x) +:$ f(x) -$ f(a, b) +:$ f(a, b) diff --git a/test/tests/function custom type dispatch error.ans b/test/tests/function custom type dispatch error.ans index 231cf35..c0b3a6f 100644 --- a/test/tests/function custom type dispatch error.ans +++ b/test/tests/function custom type dispatch error.ans @@ -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) diff --git a/test/tests/function custom type dispatch.ans b/test/tests/function custom type dispatch.ans index d257609..c627143 100644 --- a/test/tests/function custom type dispatch.ans +++ b/test/tests/function custom type dispatch.ans @@ -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) diff --git a/test/tests/function cycle.ans b/test/tests/function cycle.ans index 132f48f..5aae6f2 100644 --- a/test/tests/function cycle.ans +++ b/test/tests/function cycle.ans @@ -1,9 +1,9 @@ -$ f - $ a +:$ f + :$ a a - $ b + :$ b b - $ c + :$ c c ~ cycle(&a,&b,&c) diff --git a/test/tests/function decorator scope explicit call.ans b/test/tests/function decorator scope explicit call.ans deleted file mode 100644 index ab738c9..0000000 --- a/test/tests/function decorator scope explicit call.ans +++ /dev/null @@ -1,3 +0,0 @@ -a.👁️: {a.👁️} $ a - -~ a() \ No newline at end of file diff --git a/test/tests/function decorator scope implicit call.ans b/test/tests/function decorator scope implicit call.ans deleted file mode 100644 index b59b640..0000000 --- a/test/tests/function decorator scope implicit call.ans +++ /dev/null @@ -1,9 +0,0 @@ -$ f - ko - a.👁️: {a.👁️} $ a - ok - -~ f.a - -In function: -~ f diff --git a/test/tests/function decorator scope.ans b/test/tests/function decorator scope.ans deleted file mode 100644 index ebf1f0d..0000000 --- a/test/tests/function decorator scope.ans +++ /dev/null @@ -1 +0,0 @@ -a.👁️: {a.👁️} $ a diff --git a/test/tests/function name dispatch.ans b/test/tests/function name dispatch.ans index 0f085fe..643b56b 100644 --- a/test/tests/function name dispatch.ans +++ b/test/tests/function name dispatch.ans @@ -1,7 +1,7 @@ -$ fn(x) +:$ fn(x) x -$ fn(a) +:$ fn(a) a ~ fn(a=5) diff --git a/test/tests/function next.ans b/test/tests/function next.ans index df29021..c4eb9c3 100644 --- a/test/tests/function next.ans +++ b/test/tests/function next.ans @@ -1,9 +1,9 @@ -$ f - $ a +:$ f + :$ a a - $ b + :$ b b - $ c + :$ c c ~ next(&a, &b, &c) diff --git a/test/tests/function no conflict.ans b/test/tests/function no conflict.ans index 8625326..ea799ab 100644 --- a/test/tests/function no conflict.ans +++ b/test/tests/function no conflict.ans @@ -1,5 +1,5 @@ -$ f(a, b) +:$ f(a, b) -$ f(x) +:$ f(x) -$ f(u, v) +:$ f(u, v) diff --git a/test/tests/function random.ans b/test/tests/function random.ans index d2ef400..a788abf 100644 --- a/test/tests/function random.ans +++ b/test/tests/function random.ans @@ -1,9 +1,9 @@ -$ f - $ a +:$ f + :$ a a - $ b + :$ b b - $ c + :$ c c ~ random(&a,&b,&c) diff --git a/test/tests/function reference call explicit call.ans b/test/tests/function reference call explicit call.ans index 2c117ed..6ee1ce4 100644 --- a/test/tests/function reference call explicit call.ans +++ b/test/tests/function reference call explicit call.ans @@ -1,6 +1,6 @@ -$ fn +:$ fn 1 - § c + :! c 2 :c = &fn diff --git a/test/tests/function reference call.ans b/test/tests/function reference call.ans index a985a25..a7d108d 100644 --- a/test/tests/function reference call.ans +++ b/test/tests/function reference call.ans @@ -1,7 +1,7 @@ -$ f(x) +:$ f(x) @x+2 -$ g(x) +:$ g(x) @x+3 :a = &f diff --git a/test/tests/function reference chain call.ans b/test/tests/function reference chain call.ans index c3460bf..0a1af4b 100644 --- a/test/tests/function reference chain call.ans +++ b/test/tests/function reference chain call.ans @@ -1,7 +1,7 @@ -$ fn +:$ fn @1 -$ add(x) +:$ add(x) @x+2 :c = &fn diff --git a/test/tests/function reference dot operator function.ans b/test/tests/function reference dot operator function.ans index f59f9f3..1bcda95 100644 --- a/test/tests/function reference dot operator function.ans +++ b/test/tests/function reference dot operator function.ans @@ -1,5 +1,5 @@ -$ f - $ a +:$ f + :$ a @12 :x = &f diff --git a/test/tests/function reference dot operator.ans b/test/tests/function reference dot operator.ans index 4a7ec38..e4f040b 100644 --- a/test/tests/function reference dot operator.ans +++ b/test/tests/function reference dot operator.ans @@ -1,4 +1,4 @@ -$ f +:$ f :a = 12 :x = &f diff --git a/test/tests/function return exit function nested.ans b/test/tests/function return exit function nested.ans index 7c7d87a..c0fae57 100644 --- a/test/tests/function return exit function nested.ans +++ b/test/tests/function return exit function nested.ans @@ -1,5 +1,5 @@ -$ hey - § foo +:$ hey + :! foo @2 @3 @5 diff --git a/test/tests/function return exit function.ans b/test/tests/function return exit function.ans index c1799f0..c1da341 100644 --- a/test/tests/function return exit function.ans +++ b/test/tests/function return exit function.ans @@ -1,4 +1,4 @@ -$ hey +:$ hey @5 a @2 diff --git a/test/tests/function return nested.ans b/test/tests/function return nested.ans index 4ffc969..28ba74f 100644 --- a/test/tests/function return nested.ans +++ b/test/tests/function return nested.ans @@ -1,5 +1,5 @@ -$ hey - § foo +:$ hey + :! foo @2 @5 diff --git a/test/tests/function return.ans b/test/tests/function return.ans index 8fe7034..90619ef 100644 --- a/test/tests/function return.ans +++ b/test/tests/function return.ans @@ -1,4 +1,4 @@ -$ hey +:$ hey @5 {hey} \ No newline at end of file diff --git a/test/tests/function scope wrong.ans b/test/tests/function scope wrong.ans index 20a6f65..d3a4e28 100644 --- a/test/tests/function scope wrong.ans +++ b/test/tests/function scope wrong.ans @@ -1,4 +1,4 @@ -$ a +:$ a :b = 5 a: {b} diff --git a/test/tests/function scope.ans b/test/tests/function scope.ans index 50350ee..7378c49 100644 --- a/test/tests/function scope.ans +++ b/test/tests/function scope.ans @@ -1,4 +1,4 @@ -$ a +:$ a :b = 5 a: {a.b} diff --git a/test/tests/function scoped mutable.ans b/test/tests/function scoped mutable.ans index 382ce8a..219ba84 100644 --- a/test/tests/function scoped mutable.ans +++ b/test/tests/function scoped mutable.ans @@ -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) diff --git a/test/tests/function scoped recursive.ans b/test/tests/function scoped recursive.ans index c4f9e00..6a409ee 100644 --- a/test/tests/function scoped recursive.ans +++ b/test/tests/function scoped recursive.ans @@ -1,6 +1,6 @@ :n = 0 -$ f(c=1) +:$ f(c=1) :a = 1 start: {a} diff --git a/test/tests/function scoped.ans b/test/tests/function scoped.ans index c09d358..d61e4bf 100644 --- a/test/tests/function scoped.ans +++ b/test/tests/function scoped.ans @@ -1,11 +1,11 @@ -$ f() +:$ f() :a = 1 {a} ~ a := a + 1 -$ g +:$ g :a = 1 {a} diff --git a/test/tests/function selection.ans b/test/tests/function selection.ans index 2c3c81e..04ce4c6 100644 --- a/test/tests/function selection.ans +++ b/test/tests/function selection.ans @@ -1,8 +1,8 @@ -$ a(x::number) +:$ a(x::number) @x + 2 -$ x - $ a(x::string) +:$ x + :$ a(x::string) @x + "heh" {a("plop")} diff --git a/test/tests/function separate variable from variants.ans b/test/tests/function separate variable from variants.ans index ff58d35..9b656e8 100644 --- a/test/tests/function separate variable from variants.ans +++ b/test/tests/function separate variable from variants.ans @@ -1,10 +1,10 @@ -$ f +:$ f :a = 2 -$ f(x) +:$ f(x) :a = 5 -$ f(b) +:$ f(b) :a = 10 {f.a} = 2 diff --git a/test/tests/function type dispatch ambigous.ans b/test/tests/function type dispatch ambigous.ans index 54eb3b3..52ffba8 100644 --- a/test/tests/function type dispatch ambigous.ans +++ b/test/tests/function type dispatch ambigous.ans @@ -1,7 +1,7 @@ -$ fn(x::number) +:$ fn(x::number) x -$ fn(a::number) +:$ fn(a::number) a ~ fn(5) diff --git a/test/tests/function type dispatch with default.ans b/test/tests/function type dispatch with default.ans index 12762ce..48c460a 100644 --- a/test/tests/function type dispatch with default.ans +++ b/test/tests/function type dispatch with default.ans @@ -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")} diff --git a/test/tests/function type dispatch.ans b/test/tests/function type dispatch.ans index 8670a8d..315f56c 100644 --- a/test/tests/function type dispatch.ans +++ b/test/tests/function type dispatch.ans @@ -1,7 +1,7 @@ -$ fn(x::number) +:$ fn(x::number) x -$ fn(a::string) +:$ fn(a::string) a ~ fn("s") diff --git a/test/tests/function ufcs arg.ans b/test/tests/function ufcs arg.ans index ef35aaf..530e957 100644 --- a/test/tests/function ufcs arg.ans +++ b/test/tests/function ufcs arg.ans @@ -1,4 +1,4 @@ -$ f(a) +:$ f(a) {a} ~ "ok"!f diff --git a/test/tests/function ufcs args.ans b/test/tests/function ufcs args.ans index f70e5db..896c6c7 100644 --- a/test/tests/function ufcs args.ans +++ b/test/tests/function ufcs args.ans @@ -1,4 +1,4 @@ -$ f(a, b) +:$ f(a, b) {a}{b} ~ "o"!f("k") diff --git a/test/tests/function vararg empty.ans b/test/tests/function vararg empty.ans index 3f4f503..f521e78 100644 --- a/test/tests/function vararg empty.ans +++ b/test/tests/function vararg empty.ans @@ -1,4 +1,4 @@ -$ f(l...) +:$ f(l...) {l} ~ f() diff --git a/test/tests/function vararg.ans b/test/tests/function vararg.ans index 6dc3ab2..b7aa5da 100644 --- a/test/tests/function vararg.ans +++ b/test/tests/function vararg.ans @@ -1,4 +1,4 @@ -$ f(l...) +:$ f(l...) {l} ~ f("o", "k") diff --git a/test/tests/function.ans b/test/tests/function.ans index 875ebe5..3276153 100644 --- a/test/tests/function.ans +++ b/test/tests/function.ans @@ -1,4 +1,4 @@ -$ f +:$ f ok ~ f diff --git a/test/tests/immediately run function explicit call.ans b/test/tests/immediately run function explicit call.ans new file mode 100644 index 0000000..a9bebc7 --- /dev/null +++ b/test/tests/immediately run function explicit call.ans @@ -0,0 +1,4 @@ +:~$ a + a.👁️: {a.👁️} + +~ a() \ No newline at end of file diff --git a/test/tests/function decorator scope explicit call.lua b/test/tests/immediately run function explicit call.lua similarity index 100% rename from test/tests/function decorator scope explicit call.lua rename to test/tests/immediately run function explicit call.lua diff --git a/test/tests/immediately run function implicit call.ans b/test/tests/immediately run function implicit call.ans new file mode 100644 index 0000000..57482a7 --- /dev/null +++ b/test/tests/immediately run function implicit call.ans @@ -0,0 +1,10 @@ +:$ f + ko + :~$ a + a.👁️: {a.👁️} + ok + +~ f.a + +In function: +~ f diff --git a/test/tests/function decorator scope implicit call.lua b/test/tests/immediately run function implicit call.lua similarity index 100% rename from test/tests/function decorator scope implicit call.lua rename to test/tests/immediately run function implicit call.lua diff --git a/test/tests/immediately run function scope.ans b/test/tests/immediately run function scope.ans new file mode 100644 index 0000000..47ea1f3 --- /dev/null +++ b/test/tests/immediately run function scope.ans @@ -0,0 +1,2 @@ +:~$ a + a.👁️: {a.👁️} diff --git a/test/tests/function decorator scope.lua b/test/tests/immediately run function scope.lua similarity index 100% rename from test/tests/function decorator scope.lua rename to test/tests/immediately run function scope.lua diff --git a/test/tests/immediately run variable.ans b/test/tests/immediately run variable.ans new file mode 100644 index 0000000..067d9fe --- /dev/null +++ b/test/tests/immediately run variable.ans @@ -0,0 +1,4 @@ +:$ a + a.👁️: {a.👁️} + +:~ b = &a diff --git a/test/tests/immediately run variable.lua b/test/tests/immediately run variable.lua new file mode 100644 index 0000000..0273939 --- /dev/null +++ b/test/tests/immediately run variable.lua @@ -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" } +]]-- \ No newline at end of file diff --git a/test/tests/implicit call of references.ans b/test/tests/implicit call of references.ans index f6590fb..fa04b23 100644 --- a/test/tests/implicit call of references.ans +++ b/test/tests/implicit call of references.ans @@ -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 diff --git a/test/tests/interrupt callback nested paragraph.ans b/test/tests/interrupt callback nested paragraph.ans index 05a2002..f945e45 100644 --- a/test/tests/interrupt callback nested paragraph.ans +++ b/test/tests/interrupt callback nested paragraph.ans @@ -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} diff --git a/test/tests/interrupt callback nested.ans b/test/tests/interrupt callback nested.ans index cd6f459..bbf13ac 100644 --- a/test/tests/interrupt callback nested.ans +++ b/test/tests/interrupt callback nested.ans @@ -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} diff --git a/test/tests/interrupt callback.ans b/test/tests/interrupt callback.ans index 66811e5..609755f 100644 --- a/test/tests/interrupt callback.ans +++ b/test/tests/interrupt callback.ans @@ -1,16 +1,16 @@ -$ bar +:$ bar :var = 5 ~ var := 2 - $ leave + :$ leave in interrupt: {var} before: {var} ~ interrupt("leave") - § foo + :! foo checkpoint after: {var} diff --git a/test/tests/interrupt no callback.ans b/test/tests/interrupt no callback.ans index 7bf52f1..de97996 100644 --- a/test/tests/interrupt no callback.ans +++ b/test/tests/interrupt no callback.ans @@ -1,16 +1,16 @@ -$ bar +:$ bar :var = 5 ~ var := 2 - $ leave + :$ leave in interrupt: {var} before: {var} ~ interrupt() - § foo + :! foo checkpoint after: {var} diff --git a/test/tests/lazy boolean operators.ans b/test/tests/lazy boolean operators.ans index 5a945bc..ec1d138 100644 --- a/test/tests/lazy boolean operators.ans +++ b/test/tests/lazy boolean operators.ans @@ -1,8 +1,8 @@ -$ a +:$ a a @1 -$ b +:$ b b @0 diff --git a/test/tests/map index accross checkpoints.ans b/test/tests/map index accross checkpoints.ans index 54abbe2..29961fd 100644 --- a/test/tests/map index accross checkpoints.ans +++ b/test/tests/map index accross checkpoints.ans @@ -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)} diff --git a/test/tests/merge nested mutable bis.ans b/test/tests/merge nested mutable bis.ans index 952b4a3..6503334 100644 --- a/test/tests/merge nested mutable bis.ans +++ b/test/tests/merge nested mutable bis.ans @@ -5,13 +5,13 @@ ~ a!insert(b) -§ c +:! c ~ b!insert(3) -§ d +:! d ~ b!insert(4) -$ check +:$ check \[1,\[2,3,4]]: {a} diff --git a/test/tests/merge nested mutable error bis.ans b/test/tests/merge nested mutable error bis.ans index e36a041..24a95ef 100644 --- a/test/tests/merge nested mutable error bis.ans +++ b/test/tests/merge nested mutable error bis.ans @@ -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} diff --git a/test/tests/merge nested mutable error.ans b/test/tests/merge nested mutable error.ans index 767c70f..973168c 100644 --- a/test/tests/merge nested mutable error.ans +++ b/test/tests/merge nested mutable error.ans @@ -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} diff --git a/test/tests/merge nested mutable.ans b/test/tests/merge nested mutable.ans index af459c6..2efcba6 100644 --- a/test/tests/merge nested mutable.ans +++ b/test/tests/merge nested mutable.ans @@ -5,13 +5,13 @@ ~ a!insert(b) -§ c +:! c ~ b!insert(3) -§ d +:! d ~ a!insert(4) -$ check +:$ check \[1,\[2,3],4]: {a} diff --git a/test/tests/named arguments.ans b/test/tests/named arguments.ans index d819f40..ee0ef59 100644 --- a/test/tests/named arguments.ans +++ b/test/tests/named arguments.ans @@ -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")} diff --git a/test/tests/named varag.ans b/test/tests/named varag.ans index 3d7ed1d..02bd0c0 100644 --- a/test/tests/named varag.ans +++ b/test/tests/named varag.ans @@ -1,4 +1,4 @@ -$ f(l...) +:$ f(l...) ~ l!len :a = 0 ~ a := l(1) diff --git a/test/tests/object comparaison.ans b/test/tests/object comparaison.ans index af40f6e..7551505 100644 --- a/test/tests/object comparaison.ans +++ b/test/tests/object comparaison.ans @@ -1,4 +1,4 @@ -% class +:% class :a:b = "foo" :c = "bar" diff --git a/test/tests/object constructor.ans b/test/tests/object constructor.ans index 4de82c5..c3b5fa4 100644 --- a/test/tests/object constructor.ans +++ b/test/tests/object constructor.ans @@ -1,8 +1,8 @@ -% class +:% class :a:b = "foo" :c = "bar" -$ new(o::&class, x) +:$ new(o::&class, x) ~ o.c := x @o diff --git a/test/tests/object several.ans b/test/tests/object several.ans index 1c9fc94..a72231b 100644 --- a/test/tests/object several.ans +++ b/test/tests/object several.ans @@ -1,4 +1,4 @@ -% class +:% class :a:b = "foo" :c = "bar" diff --git a/test/tests/object simple.ans b/test/tests/object simple.ans index aae5277..081a3c2 100644 --- a/test/tests/object simple.ans +++ b/test/tests/object simple.ans @@ -1,4 +1,4 @@ -% class +:% class :a:b = "foo" :c = "bar" diff --git a/test/tests/optional arguments.ans b/test/tests/optional arguments.ans index 770b906..4dde1c0 100644 --- a/test/tests/optional arguments.ans +++ b/test/tests/optional arguments.ans @@ -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")} diff --git a/test/tests/paragraph alias.ans b/test/tests/paragraph alias.ans index f18958d..6dafa7d 100644 --- a/test/tests/paragraph alias.ans +++ b/test/tests/paragraph alias.ans @@ -1,4 +1,4 @@ -§ f : test +:! f : test @"ok" {f} = {test} diff --git a/test/tests/paragraph run force.ans b/test/tests/paragraph run force.ans index 5801def..de2106c 100644 --- a/test/tests/paragraph run force.ans +++ b/test/tests/paragraph run force.ans @@ -1,6 +1,6 @@ -$ f +:$ f x - § p + :! p a b diff --git a/test/tests/paragraph run from.ans b/test/tests/paragraph run from.ans index 0638147..72cc7a8 100644 --- a/test/tests/paragraph run from.ans +++ b/test/tests/paragraph run from.ans @@ -1,6 +1,6 @@ -$ f +:$ f x - § p + :! p a b diff --git a/test/tests/paragraph run.ans b/test/tests/paragraph run.ans index d064014..cc68f38 100644 --- a/test/tests/paragraph run.ans +++ b/test/tests/paragraph run.ans @@ -1,6 +1,6 @@ -$ f +:$ f x - § p + :! p a b diff --git a/test/tests/paragraph.ans b/test/tests/paragraph.ans index 21c9580..8808a29 100644 --- a/test/tests/paragraph.ans +++ b/test/tests/paragraph.ans @@ -1,3 +1,3 @@ -§ p +:! p a b \ No newline at end of file diff --git a/test/tests/resume from nested paragraph.ans b/test/tests/resume from nested paragraph.ans index 6246246..f2fad80 100644 --- a/test/tests/resume from nested paragraph.ans +++ b/test/tests/resume from nested paragraph.ans @@ -1,9 +1,9 @@ -$ f +:$ f x - § p + :! p a - § q + :! q b c diff --git a/test/tests/resume from paragraph restore tags.ans b/test/tests/resume from paragraph restore tags.ans index 9124c78..06d3965 100644 --- a/test/tests/resume from paragraph restore tags.ans +++ b/test/tests/resume from paragraph restore tags.ans @@ -1,9 +1,9 @@ -$ f +:$ f # "a"="a" a ~ 1 # "x"="x" # "b"="b" - § p + :! p b # "c"="c" c diff --git a/test/tests/resume from paragraph with nested choice.ans b/test/tests/resume from paragraph with nested choice.ans index 6b178a7..98014c2 100644 --- a/test/tests/resume from paragraph with nested choice.ans +++ b/test/tests/resume from paragraph with nested choice.ans @@ -1,7 +1,7 @@ -$ f +:$ f > a -> a - § p + :! p > aa -> aa > ab @@ -18,10 +18,10 @@ $ f ~ f.p -$ g +:$ g > a -> a - § p + :! p > aa -> aa > ab @@ -38,11 +38,11 @@ $ g ~ g.p -$ h +:$ h ~ 1 > a -> a - § p + :! p > aa -> aa > ab @@ -58,10 +58,10 @@ $ h ~ h.p -$ i +:$ i > a -> a - § p + :! p > aa -> aa > ab diff --git a/test/tests/resume from paragraph with nested condition.ans b/test/tests/resume from paragraph with nested condition.ans index 9a7b7d4..54d9c87 100644 --- a/test/tests/resume from paragraph with nested condition.ans +++ b/test/tests/resume from paragraph with nested condition.ans @@ -1,6 +1,6 @@ -$ f +:$ f ~ 1 - § p + :! p x ~~ y @@ -9,9 +9,9 @@ $ f ~ f.p -$ g +:$ g ~ 0 - § p + :! p x ~~ y diff --git a/test/tests/return children.ans b/test/tests/return children.ans index 452a8a4..621bce1 100644 --- a/test/tests/return children.ans +++ b/test/tests/return children.ans @@ -1,4 +1,4 @@ -$ fn +:$ fn :i=0 @i ~ i:=5 @@ -6,7 +6,7 @@ $ fn {fn} = 50 -$ g +:$ g @0 @3 diff --git a/test/tests/return in choice.ans b/test/tests/return in choice.ans index 3aa7b6d..b75041c 100644 --- a/test/tests/return in choice.ans +++ b/test/tests/return in choice.ans @@ -1,4 +1,4 @@ -$ f +:$ f > a x @1 diff --git a/test/tests/scope checkpoint mutable bis error.ans b/test/tests/scope checkpoint mutable bis error.ans index fca65ae..da436ea 100644 --- a/test/tests/scope checkpoint mutable bis error.ans +++ b/test/tests/scope checkpoint mutable bis error.ans @@ -6,13 +6,13 @@ :n = 0 -$ f(t) +:$ f(t) ~ t!insert(len(l)+1) f1: {l} {t} CHECK - § c + :! c ~ n < 1 REC @@ -25,7 +25,7 @@ $ f(t) f2: {l} CHECK 2 - § d + :! d ~ t!insert(len(t)+1) @@ -43,7 +43,7 @@ l: {l} x: {x} -$ check +:$ check AFTER ERROR l: {l} \ No newline at end of file diff --git a/test/tests/scope checkpoint mutable bis.ans b/test/tests/scope checkpoint mutable bis.ans index d4af43b..1476b84 100644 --- a/test/tests/scope checkpoint mutable bis.ans +++ b/test/tests/scope checkpoint mutable bis.ans @@ -4,13 +4,13 @@ :n = 0 -$ f(t) +:$ f(t) ~ t!insert(len(l)+1) f1: {l} {t} CHECK - § c + :! c ~ n < 1 REC @@ -23,7 +23,7 @@ $ f(t) f2: {l} CHECK 2 - § d + :! d ~ t!insert(len(t)+1) diff --git a/test/tests/scope checkpoint mutable error.ans b/test/tests/scope checkpoint mutable error.ans index 3fbdcfa..1fb6c4e 100644 --- a/test/tests/scope checkpoint mutable error.ans +++ b/test/tests/scope checkpoint mutable error.ans @@ -4,13 +4,13 @@ :n = 0 -$ f(t) +:$ f(t) ~ t!insert(len(l)+1) f1: {l} {t} CHECK - § c + :! c ~ n < 1 REC @@ -32,7 +32,7 @@ FINAL l: {l} -$ check +:$ check AFTER ERROR l: {l} \ No newline at end of file diff --git a/test/tests/scope checkpoint mutable ter error.ans b/test/tests/scope checkpoint mutable ter error.ans index 2c70ade..560a7c3 100644 --- a/test/tests/scope checkpoint mutable ter error.ans +++ b/test/tests/scope checkpoint mutable ter error.ans @@ -6,13 +6,13 @@ :n = 0 -$ f(t) +:$ f(t) ~ t!insert(len(l)+1) f1: {l} {t} CHECK - § c + :! c ~ n < 1 REC @@ -27,7 +27,7 @@ $ f(t) f2: {l} CHECK 2 - § d + :! d ~ t!insert(len(t)+1) @@ -45,7 +45,7 @@ l: {l} x: {x} -$ check +:$ check AFTER ERROR l: {l} \ No newline at end of file diff --git a/test/tests/scope checkpoint mutable ter.ans b/test/tests/scope checkpoint mutable ter.ans index de9db86..4ca598b 100644 --- a/test/tests/scope checkpoint mutable ter.ans +++ b/test/tests/scope checkpoint mutable ter.ans @@ -4,13 +4,13 @@ :n = 0 -$ f(t) +:$ f(t) ~ t!insert(len(l)+1) f1: {l} {t} CHECK - § c + :! c ~ n < 1 REC @@ -25,7 +25,7 @@ $ f(t) f2: {l} CHECK 2 - § d + :! d ~ t!insert(len(t)+1) diff --git a/test/tests/scope checkpoint mutable.ans b/test/tests/scope checkpoint mutable.ans index 29f459b..dde76a8 100644 --- a/test/tests/scope checkpoint mutable.ans +++ b/test/tests/scope checkpoint mutable.ans @@ -2,13 +2,13 @@ :n = 0 -$ f(t) +:$ f(t) ~ t!insert(len(l)+1) f1: {l} {t} CHECK - § c + :! c ~ n < 1 REC diff --git a/test/tests/subtext.ans b/test/tests/subtext.ans index a8a7353..afdc802 100644 --- a/test/tests/subtext.ans +++ b/test/tests/subtext.ans @@ -1,4 +1,4 @@ -$ button +:$ button A # 2=2 Press diff --git a/test/tests/tag operator.ans b/test/tests/tag operator.ans index 90e7729..862c6e3 100644 --- a/test/tests/tag operator.ans +++ b/test/tests/tag operator.ans @@ -1,4 +1,4 @@ -$ f +:$ f b a {f # 5} c diff --git a/test/tests/text line interpolation with choice event.ans b/test/tests/text line interpolation with choice event.ans index 3dbf8a3..08afbb8 100644 --- a/test/tests/text line interpolation with choice event.ans +++ b/test/tests/text line interpolation with choice event.ans @@ -1,6 +1,6 @@ Press {jump button} to jump. -$ jump button +:$ jump button A # 1 ~ choose(1) > Surprise choice! @@ -8,7 +8,7 @@ $ jump button Use {move axis} to move. -$ move axis +:$ move axis left # 1 ~ choose(1) > Surprise choice! diff --git a/test/tests/text line interpolation with event flush.ans b/test/tests/text line interpolation with event flush.ans index c06e181..4af72d0 100644 --- a/test/tests/text line interpolation with event flush.ans +++ b/test/tests/text line interpolation with event flush.ans @@ -1,13 +1,13 @@ Press {jump button} to jump. -$ jump button +:$ jump button A # 1 @ Use {move axis} to move. -$ move axis +:$ move axis left # 1 @" joystick" diff --git a/test/tests/text line interpolation with text event.ans b/test/tests/text line interpolation with text event.ans index acb03f5..7103768 100644 --- a/test/tests/text line interpolation with text event.ans +++ b/test/tests/text line interpolation with text event.ans @@ -1,10 +1,10 @@ Press {jump button} to jump. -$ jump button +:$ jump button A # 1 Use {move axis} to move. -$ move axis +:$ move axis left # 1 @" joystick" diff --git a/test/tests/unary operator overload.ans b/test/tests/unary operator overload.ans index ead4a01..50e25d3 100644 --- a/test/tests/unary operator overload.ans +++ b/test/tests/unary operator overload.ans @@ -1,7 +1,7 @@ -$ -_(f) +:$ -_(f) @"generic minus" -$ -_(f::string) +:$ -_(f::string) @"minus "+f {-5} diff --git a/test/tests/unseen line.ans b/test/tests/unseen line.ans index 95b3be7..913add7 100644 --- a/test/tests/unseen line.ans +++ b/test/tests/unseen line.ans @@ -1,4 +1,4 @@ -$ x +:$ x a seen only once ~ !seen b