mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
Improve naming consistency
expression/conditions -> conditions paragraphs/checkpoints -> checkpoints merge/flush/commit -> merge
This commit is contained in:
parent
b7f38a16fd
commit
6f564ea0e2
6 changed files with 73 additions and 73 deletions
66
README.md
66
README.md
|
|
@ -31,7 +31,7 @@ And things that are halfway there but *should* be there eventually (i.e., TODO):
|
|||
* language independant; scripts should (hopefully) be easily localizable into any language (it's possible, but doesn't provide any batteries for this right now)
|
||||
Defaults variables use emoji and then it's expected to alias them; works but not the most satisfying solution.
|
||||
* a good documentation
|
||||
Need to work on consistent naming (paragraphs/checkpoints/commit, call syntaxes)
|
||||
Need to work on consistent naming of Anselme concepts
|
||||
A step by step tutorial
|
||||
|
||||
Things that Anselme is not:
|
||||
|
|
@ -86,11 +86,11 @@ Another line.
|
|||
random line whith indentation which makes no sense at all.
|
||||
```
|
||||
|
||||
#### Commiting / checkpoints
|
||||
#### Checkpoints
|
||||
|
||||
When executing a piece of Anselme code, it will not directly modify the global state (i.e. the values of variables used by every script), but only locally, in this execution.
|
||||
|
||||
Right after reaching a checkpoint (a paragraph line), Anselme will commit its local state into the global one, i.e., make every change accessible to other scripts.
|
||||
Right after reaching a checkpoint (line or decorator), Anselme will merge the local state with the global one, i.e., make every change accessible to other scripts.
|
||||
|
||||
```
|
||||
$ main
|
||||
|
|
@ -103,7 +103,7 @@ $ main
|
|||
(But if we run the script "parallel" in parallel at this point, it will still think var=5)
|
||||
|
||||
§ foo
|
||||
But the variable will be commited to the global state on a checkpoint
|
||||
But the variable will be merged with the global state on a checkpoint
|
||||
|
||||
after: {var}=2, still, as expected
|
||||
|
||||
|
|
@ -117,9 +117,9 @@ $ parallel
|
|||
|
||||
The purpose of this system is both to allow several scripts to run at the same time with an easy way to avoid interferences, and to make sure the global state is always in a consistent (and not in the middle of a calculation): since scripts can be interrupted at any time, when it is interrupted, anything that was changed between the last checkpoint and the interruption will be discarded. When running the script again, it will resume correctly at the last reached checkpoint. See [function calls](#function-calls) for more details on how to call/resume a function.
|
||||
|
||||
Checkpoints are set per function. Paragraphs are expected to be defined inside functions only.
|
||||
Checkpoints are set per function, and are expected to be defined inside functions only.
|
||||
|
||||
Commiting also happens after a paragraph has been manually called or resumed from.
|
||||
State merging also happens after a checkpoint has been manually called or resumed from.
|
||||
|
||||
### Lines types
|
||||
|
||||
|
|
@ -137,9 +137,9 @@ There's different types of lines, depending on their first character(s) (after i
|
|||
here
|
||||
```
|
||||
|
||||
* `~`: expression line. Can be followed by an [expression](#expressions); otherwise the expression `1` is assumed. If the expression evaluates to [true](#truethness), run its children.
|
||||
* `~`: 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 expression. Same as an expression line, but is only run if the last expression or else-expression line (in the same indentation block) was false (regardless of line distance).
|
||||
* `~~`: 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).
|
||||
|
||||
```
|
||||
~ 1
|
||||
|
|
@ -164,7 +164,7 @@ There's different types of lines, depending on their first character(s) (after i
|
|||
> Last choice
|
||||
```
|
||||
|
||||
* `$`: 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.
|
||||
* `$`: 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.
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -215,15 +215,15 @@ Functions can return a value using a [return line](#lines-that-can-t-have-childr
|
|||
Functions always have the following variables defined in its namespace by default:
|
||||
|
||||
`👁️`: number, number of times the function was executed before
|
||||
`🏁`: string, name of last reached checkpoint/paragraph
|
||||
`🏁`: string, name of last reached checkpoint
|
||||
|
||||
* `§`: paragraph. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases). Define a paragraph. A paragraph act as a checkpoint.
|
||||
* `§`: checkpoint. Followed by an [identifier](#identifiers), then eventually an [alias](#aliases). Define a checkpoint. Also define a new namespace for its children.
|
||||
|
||||
The function 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](#paragraph-calls) to see the different ways of calling a paragraph.
|
||||
The function 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.
|
||||
|
||||
It is a checkpoint and will commit variables when the line is reached. See [committing](#committing-checkpoints).
|
||||
The local interpreter state will be merged with the global state when the line is reached. See [checkpoints](#checkpoints).
|
||||
|
||||
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 paragraph'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.
|
||||
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
|
||||
|
|
@ -233,9 +233,9 @@ $ inane dialog
|
|||
(further dialog here)
|
||||
```
|
||||
|
||||
Paragraphs always have the following variable defined in its namespace by default:
|
||||
Checkpoints always have the following variable defined in its namespace by default:
|
||||
|
||||
`👁️`: number, number of times the paragraph was reached or executed before
|
||||
`👁️`: number, number of times the checkpoint was reached or executed before
|
||||
|
||||
* `#`: tag line. Can be followed by an [expression](#expressions); otherwise nil expression is assumed. The results of the [expression](#expressions) will be added to the tags send along with any event sent from its children. Can be nested.
|
||||
|
||||
|
|
@ -298,9 +298,9 @@ And this is more text, in a different event.
|
|||
|
||||
Every line can also be followed with decorators, which are appended at the end of the line and affect its behaviour.
|
||||
|
||||
* `~`: expression decorator. Same as an expression line, behaving as if this line was it sole child. Typically used to conditionally execute line. Does not affect following else-conditions.
|
||||
* `~`: condition decorator. Same as an condition line, behaving as if this line was it sole child. Typically used to conditionally execute line. Does not affect following else-conditions.
|
||||
|
||||
* `§`: paragraph decorator. Same as a paragraph line, behaving as if this line was it sole child.
|
||||
* `§`: checkpoint decorator. Same as a checkpoint line, behaving as if this line was it sole child.
|
||||
|
||||
* `#`: tag decorator. Same as a tag line, behaving as if this line was it sole child.
|
||||
|
||||
|
|
@ -366,7 +366,7 @@ Every event have a type (`text`, `choice`, `return` or `error` by default, custo
|
|||
|
||||
Valid identifiers must be at least 1 caracters long and can contain anything except the caracters `%/*+-()!&|=$§?><:{}[],\`. They can contain spaces.
|
||||
|
||||
When defining an identifier (using a function, paragraph or variable delcaration line), it will be defined into the current namespace (defined by the parent function/paragraph). When evaluating an expression, Anselme will look for variables into the current line's namespace, then go up a level if it isn't found, and so on.
|
||||
When defining an identifier (using a function, checkpoint or variable delcaration line), it will be defined into the current namespace (defined by the parent function/checkpoint). When evaluating an expression, Anselme will look for variables into the current line's namespace, then go up a level if it isn't found, and so on.
|
||||
|
||||
In practise, this means you have to use the "genealogy" of the variable to refer to it from a line not in it indentation block:
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ Var1 in the fn1 namespace = 2: {fn1.var1}
|
|||
|
||||
#### Aliases
|
||||
|
||||
When defining identifiers (in variables, functions or paragraph definitions), they can be followed by a colon and another identifier. This identifier can be used as a new way to access the identifier (i.e., an alias).
|
||||
When defining identifiers (in variables, functions or checkpoint definitions), they can be followed by a colon and another identifier. This identifier can be used as a new way to access the identifier (i.e., an alias).
|
||||
|
||||
```
|
||||
:42 name: alias
|
||||
|
|
@ -424,7 +424,7 @@ Hi {player name}!
|
|||
Salut {nom du joueur} !
|
||||
```
|
||||
|
||||
Variables that are defined automatically by Anselme (`👁️` and `🏁` in paragraphs and functions) can be automatically aliased using `vm:setaliases("👁️alias", "🏁alias")`. See [API](#api-reference).
|
||||
Variables that are defined automatically by Anselme (`👁️` and `🏁` in checkpoints and functions) can be automatically aliased using `vm:setaliases("👁️alias", "🏁alias")`. See [API](#api-reference).
|
||||
|
||||
### Expressions
|
||||
|
||||
|
|
@ -490,7 +490,7 @@ $ f(a)
|
|||
~ f("an argument")
|
||||
```
|
||||
|
||||
Please note, however, that if the function contains checkpoints/paragraphs, 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:
|
||||
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
|
||||
|
|
@ -533,9 +533,9 @@ $ f
|
|||
this is text: {f}
|
||||
```
|
||||
|
||||
#### Paragraph calls
|
||||
#### Checkpoint calls
|
||||
|
||||
Most of the time, you should'nt need to call paragraphs yourself - they will be automatically be set as the active checkpoint when the interperter reach their line, and they will be automatically called when resuming its parent function.
|
||||
Most of the time, you should'nt need to call checkpoints yourself - they will be automatically be set as the active checkpoint when the interperter reach their line, and they will be automatically called when resuming its parent function.
|
||||
|
||||
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:
|
||||
|
||||
|
|
@ -546,17 +546,17 @@ $ f
|
|||
b
|
||||
c
|
||||
|
||||
Force run from checkpoint, will write "b" and "c" and set the current checkpoint to "checkpoint":
|
||||
Force run the function starting from checkpoint, will write "b" and "c" and set the current checkpoint to "checkpoint":
|
||||
~ f.checkpoint
|
||||
|
||||
Will correctly resumes from the checkpoint, and write "b" and "c":
|
||||
Will correctly resumes from the last set checkpoint, and write "b" and "c":
|
||||
~ f
|
||||
|
||||
Function can always be restarted from the begining using parantheses:
|
||||
~ f()
|
||||
```
|
||||
|
||||
You can also only execute the paragraphs' children code only by using a parantheses-syntax:
|
||||
You can also only execute the checkpoints' children code only by using a parantheses-syntax:
|
||||
|
||||
```
|
||||
$ f
|
||||
|
|
@ -574,13 +574,13 @@ And will resume from the checkpoint like before:
|
|||
|
||||
Method style calling is also possible, like with functions.
|
||||
|
||||
Paragraphs commit variables after being called (either manually or automatically from resuming a function). The commit always happen after the paragraph's child block has been ran.
|
||||
Checkpoints merge variables after being called (either manually or automatically from resuming a function). See [checkpoints](#checkpoints). The merge always happen after the checkpoint's child block has been ran.
|
||||
|
||||
Please also be aware that when resuming from a paragraph, Anselme will try to restore the interpreter state as if the function was correctly executed from the start up to this paragraph. This includes:
|
||||
Please also be aware that when resuming from a checkpoint, Anselme will try to restore the interpreter state as if the function was correctly executed from the start up to this checkpoint. This includes:
|
||||
|
||||
* if the paragraph is in a expression block, it will assume the expression was true (but will not re-evaluate it)
|
||||
* if the paragraph is in a choice block, it will assume this choice was selected (but will not re-evaluate any of the choices from the same choice group)
|
||||
* will try to re-add every tag from parent lines; this require Anselme to re-evaluate every tag line and decorator that's a parent of the paragraph in the function. Be careful if your tag expressions have side-effects.
|
||||
* if the checkpoint is in a condition block, it will assume the condition was true (but will not re-evaluate it)
|
||||
* if the checkpoint is in a choice block, it will assume this choice was selected (but will not re-evaluate any of the choices from the same choice group)
|
||||
* will try to re-add every tag from parent lines; this require Anselme to re-evaluate every tag line and decorator that's a parent of the checkpoint in the function. Be careful if your tag expressions have side-effects.
|
||||
|
||||
#### Operators
|
||||
|
||||
|
|
@ -650,7 +650,7 @@ This only works on strings:
|
|||
|
||||
##### Sequential execution
|
||||
|
||||
`cycle(...)`: given function/paragraph identifiers as string as arguments, will execute them in the order given each time the function is ran; e.g., `cycle("a", "b")` will execute a on the first execution, then b, then a again, etc.
|
||||
`cycle(...)`: given function/checkpoint identifiers as string as arguments, will execute them in the order given each time the function is ran; e.g., `cycle("a", "b")` will execute a on the first execution, then b, then a again, etc.
|
||||
|
||||
`next(...)`: same as cycle, but will not cycle; once the end of sequence is reached, will keep executing the last element.
|
||||
|
||||
|
|
|
|||
14
anselme.lua
14
anselme.lua
|
|
@ -14,7 +14,7 @@ local expression = require((...):gsub("anselme$", "parser.expression"))
|
|||
local eval = require((...):gsub("anselme$", "interpreter.expression"))
|
||||
local run_line = require((...):gsub("anselme$", "interpreter.interpreter")).run_line
|
||||
local to_lua = require((...):gsub("anselme$", "interpreter.common")).to_lua
|
||||
local flush_state = require((...):gsub("anselme$", "interpreter.common")).flush_state
|
||||
local merge_state = require((...):gsub("anselme$", "interpreter.common")).merge_state
|
||||
local stdfuncs = require((...):gsub("anselme$", "stdlib.functions"))
|
||||
|
||||
-- wrappers for love.filesystem / luafilesystem
|
||||
|
|
@ -55,7 +55,7 @@ local interpreter_methods = {
|
|||
vm = nil,
|
||||
|
||||
--- run the VM until the next event
|
||||
-- will commit changed variables on successful script end
|
||||
-- will merge changed variables on successful script end
|
||||
-- returns event, data; if event is "return" or "error", the interpreter must not be stepped further
|
||||
step = function(self)
|
||||
-- check status
|
||||
|
|
@ -84,7 +84,7 @@ local interpreter_methods = {
|
|||
local success, event, data = coroutine.resume(self.state.interpreter.coroutine)
|
||||
anselme.running = previous
|
||||
if not success then return "error", event end
|
||||
if event == "return" then flush_state(self.state) end
|
||||
if event == "return" then merge_state(self.state) end
|
||||
return event, data
|
||||
end,
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ local vm_mt = {
|
|||
return self
|
||||
end,
|
||||
|
||||
--- set aliases for built-in variables 👁️ and 🏁 that will be defined on every new paragraph and function
|
||||
--- set aliases for built-in variables 👁️ and 🏁 that will be defined on every new checkpoint and function
|
||||
-- nil for no alias
|
||||
-- return self
|
||||
setaliases = function(self, seen, checkpoint)
|
||||
|
|
@ -296,7 +296,7 @@ local vm_mt = {
|
|||
end,
|
||||
|
||||
--- save/load script state
|
||||
-- only saves variables full names and values, so make sure to not change important variables, paragraphs and functions names between a save and a load
|
||||
-- only saves variables full names and values, so make sure to not change important variables, checkpoints and functions names between a save and a load
|
||||
load = function(self, data)
|
||||
local saveMajor, currentMajor = data.anselme_version:match("^[^%.]*"), anselme.version:match("^[^%.]*")
|
||||
assert(saveMajor == currentMajor, ("trying to load data from an incompatible version of Anselme; save was done using %s but current version is %s"):format(data.anselme_version, anselme.version))
|
||||
|
|
@ -353,7 +353,7 @@ local vm_mt = {
|
|||
-- choice event
|
||||
choice_selected = nil,
|
||||
choice_available = {},
|
||||
-- skip next choices until next event change (to skip currently running choice block when resuming from a paragraph)
|
||||
-- skip next choices until next event change (to skip currently running choice block when resuming from a checkpoint)
|
||||
skip_choices_until_flush = nil,
|
||||
-- interrupt
|
||||
interrupt = nil,
|
||||
|
|
@ -397,7 +397,7 @@ return setmetatable(anselme, {
|
|||
-- {
|
||||
-- arity = {3,42}, type = { [1] = "variable" }, check = function, rewrite = function, vararg = 2, mode = "custom",
|
||||
-- value = function(state, exp)
|
||||
-- end -- or paragraph, function, line
|
||||
-- end -- or checkpoint, function, line
|
||||
-- }
|
||||
-- },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ local eval
|
|||
local common
|
||||
common = {
|
||||
-- flush interpreter state to global state
|
||||
flush_state = function(state)
|
||||
merge_state = function(state)
|
||||
local global_vars = state.interpreter.global_state.variables
|
||||
for var, value in pairs(state.variables) do
|
||||
global_vars[var] = value
|
||||
|
|
|
|||
|
|
@ -99,13 +99,13 @@ local function eval(state, exp)
|
|||
end
|
||||
-- anselme function
|
||||
if type(fn.value) == "table" then
|
||||
-- paragraph & paragraph decorator
|
||||
if fn.value.type == "paragraph" or fn.value.paragraph then
|
||||
-- checkpoint & checkpoint decorator
|
||||
if fn.value.type == "checkpoint" or fn.value.checkpoint then
|
||||
local r, e
|
||||
if fn.value.type == "paragraph" then
|
||||
if fn.value.type == "checkpoint" then
|
||||
r, e = run(state, fn.value.child, not exp.explicit_call)
|
||||
-- paragraph decorators: run single line or resume from it.
|
||||
-- checkpoint & seen variables will be updated from the interpreter usual paragraph-reaching code.
|
||||
-- checkpoint decorators: run single line or resume from it.
|
||||
-- checkpoint & seen variables will be updated from the interpreter usual checkpoint-reaching code.
|
||||
elseif exp.explicit_call then
|
||||
r, e = run(state, fn.value.parent_block, false, fn.value.parent_position, fn.value.parent_position)
|
||||
else
|
||||
|
|
@ -123,7 +123,7 @@ local function eval(state, exp)
|
|||
local r, e
|
||||
if exp.explicit_call or state.variables[fn.value.namespace.."🏁"].value == "" then
|
||||
r, e = run(state, fn.value.child)
|
||||
-- resume at last paragraph
|
||||
-- resume at last checkpoint
|
||||
else
|
||||
local expr, err = expression(state.variables[fn.value.namespace.."🏁"].value, state, "")
|
||||
if not expr then return expr, err end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
local eval
|
||||
local truthy, flush_state, to_lua, eval_text, escape
|
||||
local truthy, merge_state, to_lua, eval_text, escape
|
||||
|
||||
local tags = {
|
||||
--- push new tags on top of the stack, from Anselme values
|
||||
|
|
@ -148,15 +148,15 @@ local function run_line(state, line)
|
|||
end
|
||||
end
|
||||
end
|
||||
elseif line.type ~= "paragraph" then
|
||||
elseif line.type ~= "checkpoint" then
|
||||
return nil, ("unknown line type %q; at %s"):format(line.type, line.source)
|
||||
end
|
||||
-- tag decorator
|
||||
if line.tag then
|
||||
tags:pop(state)
|
||||
end
|
||||
-- paragraph decorator and line
|
||||
if line.paragraph then
|
||||
-- checkpoint decorator and line
|
||||
if line.checkpoint then
|
||||
state.variables[line.namespace.."👁️"] = {
|
||||
type = "number",
|
||||
value = state.variables[line.namespace.."👁️"].value + 1
|
||||
|
|
@ -165,7 +165,7 @@ local function run_line(state, line)
|
|||
type = "string",
|
||||
value = line.name
|
||||
}
|
||||
flush_state(state)
|
||||
merge_state(state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -195,10 +195,10 @@ run_block = function(state, block, resume_from_there, i, j)
|
|||
end
|
||||
i = i + 1
|
||||
end
|
||||
-- if we are exiting a paragraph block, mark it as ran and update checkpoint
|
||||
-- (when resuming from a checkpoint, execution is resumed from inside the paragraph, the line.paragraph check in run_line is never called)
|
||||
-- if we are exiting a checkpoint block, mark it as ran and update checkpoint
|
||||
-- (when resuming from a checkpoint, execution is resumed from inside the checkpoint, the line.checkpoint check in run_line is never called)
|
||||
-- (and we want this to be done after executing the checkpoint block anyway)
|
||||
if block.parent_line and block.parent_line.paragraph then
|
||||
if block.parent_line and block.parent_line.checkpoint then
|
||||
local parent_line = block.parent_line
|
||||
state.variables[parent_line.namespace.."👁️"] = {
|
||||
type = "number",
|
||||
|
|
@ -213,7 +213,7 @@ run_block = function(state, block, resume_from_there, i, j)
|
|||
value = parent_line.name
|
||||
}
|
||||
end
|
||||
flush_state(state)
|
||||
merge_state(state)
|
||||
end
|
||||
-- go up hierarchy if asked to resume
|
||||
-- will stop at function boundary
|
||||
|
|
@ -294,7 +294,7 @@ local interpreter = {
|
|||
package.loaded[...] = interpreter
|
||||
eval = require((...):gsub("interpreter$", "expression"))
|
||||
local common = require((...):gsub("interpreter$", "common"))
|
||||
truthy, flush_state, to_lua, eval_text = common.truthy, common.flush_state, common.to_lua, common.eval_text
|
||||
truthy, merge_state, to_lua, eval_text = common.truthy, common.merge_state, common.to_lua, common.eval_text
|
||||
escape = require((...):gsub("interpreter%.interpreter$", "parser.common")).escape
|
||||
|
||||
return interpreter
|
||||
|
|
|
|||
|
|
@ -22,21 +22,21 @@ local function parse_line(line, state, namespace)
|
|||
local expr
|
||||
l, expr = l:match("^(.-)%s*%~(.-)$")
|
||||
r.condition = expr
|
||||
-- paragraph
|
||||
-- checkpoint
|
||||
elseif l:match("^..+§.-$") then
|
||||
-- get identifier
|
||||
local name
|
||||
l, name = l:match("^(.-)%s*§(.-)$")
|
||||
local identifier, rem = name:match("^("..identifier_pattern..")(.-)$")
|
||||
if not identifier then return nil, ("no valid identifier in paragraph decorator %q; at %s"):format(identifier, line.source) end
|
||||
if not identifier then return nil, ("no valid identifier in checkpoint decorator %q; at %s"):format(identifier, line.source) end
|
||||
-- format identifier
|
||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||
-- get alias
|
||||
if rem:match("^%:") then
|
||||
local content = rem:sub(2)
|
||||
local alias, rem2 = content:match("^("..identifier_pattern..")(.-)$")
|
||||
if not alias then return nil, ("expected an identifier in alias in paragraph decorator, but got %q; at %s"):format(content, line.source) end
|
||||
if rem2:match("[^%s]") then return nil, ("expected end-of-line after identifier in alias in paragraph decorator, but got %q; at %s"):format(rem2, line.source) end
|
||||
if not alias then return nil, ("expected an identifier in alias in checkpoint decorator, but got %q; at %s"):format(content, line.source) end
|
||||
if rem2:match("[^%s]") then return nil, ("expected end-of-line after identifier in alias in checkpoint decorator, but got %q; at %s"):format(rem2, line.source) end
|
||||
-- format alias
|
||||
local aliasfqm = ("%s%s"):format(namespace, format_identifier(alias))
|
||||
-- define alias
|
||||
|
|
@ -45,11 +45,11 @@ local function parse_line(line, state, namespace)
|
|||
end
|
||||
state.aliases[aliasfqm] = fqm
|
||||
elseif rem:match("[^%s]") then
|
||||
return nil, ("expected end-of-line after identifier in paragraph decorator, but got %q; at %s"):format(rem, line.source)
|
||||
return nil, ("expected end-of-line after identifier in checkpoint decorator, but got %q; at %s"):format(rem, line.source)
|
||||
end
|
||||
-- define paragraph
|
||||
-- define checkpoint
|
||||
namespace = fqm.."."
|
||||
r.paragraph = true
|
||||
r.checkpoint = true
|
||||
r.parent_function = true
|
||||
r.namespace = fqm.."."
|
||||
r.name = fqm
|
||||
|
|
@ -104,14 +104,14 @@ local function parse_line(line, state, namespace)
|
|||
r.push_event = "choice"
|
||||
r.child = true
|
||||
r.text = l:match("^>%s*(.-)$")
|
||||
-- function & paragraph
|
||||
-- function & checkpoint
|
||||
elseif 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 = l:match("^%$") and "function" or "paragraph"
|
||||
r.type = l:match("^%$") and "function" or "checkpoint"
|
||||
r.child = true
|
||||
-- get identifier
|
||||
local lc = l:match("^%$(.*)$") or l:match("^§(.*)$")
|
||||
local identifier, rem = lc:match("^("..identifier_pattern..")(.-)$")
|
||||
if not identifier then return nil, ("no valid identifier in paragraph/function definition line %q; at %s"):format(lc, line.source) end
|
||||
if not identifier then return nil, ("no valid identifier in checkpoint/function definition line %q; at %s"):format(lc, line.source) end
|
||||
-- format identifier
|
||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||
-- get alias
|
||||
|
|
@ -119,12 +119,12 @@ local function parse_line(line, state, namespace)
|
|||
local content = rem:sub(2)
|
||||
local alias
|
||||
alias, rem = content:match("^("..identifier_pattern..")(.-)$")
|
||||
if not alias then return nil, ("expected an identifier in alias in paragraph/function definition line, but got %q; at %s"):format(content, line.source) end
|
||||
if not alias then return nil, ("expected an identifier in alias in checkpoint/function definition line, but got %q; at %s"):format(content, line.source) end
|
||||
-- format alias
|
||||
local aliasfqm = ("%s%s"):format(namespace, format_identifier(alias))
|
||||
-- define alias
|
||||
if state.aliases[aliasfqm] ~= nil and state.aliases[aliasfqm] ~= fqm then
|
||||
return nil, ("trying to define alias %q for function/paragraph %q, but already exist and refer to %q; at %s"):format(aliasfqm, fqm, state.aliases[aliasfqm], line.source)
|
||||
return nil, ("trying to define alias %q for checkpoint/function %q, but already exist and refer to %q; at %s"):format(aliasfqm, fqm, state.aliases[aliasfqm], line.source)
|
||||
end
|
||||
state.aliases[aliasfqm] = fqm
|
||||
end
|
||||
|
|
@ -159,7 +159,7 @@ local function parse_line(line, state, namespace)
|
|||
table.insert(r.params, param_fqm)
|
||||
end
|
||||
elseif rem:match("[^%s]") then
|
||||
return nil, ("expected end-of-line at end of paragraph/function definition line, but got %q; at %s"):format(rem, line.source)
|
||||
return nil, ("expected end-of-line at end of checkpoint/function definition line, but got %q; at %s"):format(rem, line.source)
|
||||
end
|
||||
local arity, vararg = #r.params, nil
|
||||
if arity > 0 and r.params[arity]:match("%.%.%.$") then -- varargs
|
||||
|
|
@ -167,9 +167,9 @@ local function parse_line(line, state, namespace)
|
|||
vararg = arity
|
||||
arity = { arity-1, math.huge }
|
||||
end
|
||||
-- store parent function and run paragraph when line is read
|
||||
if r.type == "paragraph" then
|
||||
r.paragraph = true
|
||||
-- store parent function and run checkpoint when line is read
|
||||
if r.type == "checkpoint" then
|
||||
r.checkpoint = true
|
||||
r.parent_function = true
|
||||
end
|
||||
-- don't keep function node in block AST
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue