1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 16:49:31 +00:00

Add alias() to define alias after definition; add frFR language file

This commit is contained in:
Étienne Fildadut 2021-06-05 01:30:40 +02:00
parent 198c06e2e8
commit 61e3143e9e
6 changed files with 91 additions and 23 deletions

View file

@ -819,6 +819,8 @@ This only works on strings:
`a(b)`: evaluate b (number), returns the value with this index in a (list). Use 1-based indexing. If b is a string, will search the first pair in the list with this string as its name. Operator is named `()`.
`{}(v)`: function called when formatting a value in a text interpolation for printing
#### Built-in functions
##### Pair methods
@ -847,7 +849,7 @@ This only works on strings:
##### Various
`{}(v)`: function called when formatting a value in a text interpolation for printing
`alias(identifier::string, alias::string)`: define an alias `alias` for variable `identifier`. Expect fully qualified names.
`rand([m[, n]])`: when called whitout arguments, returns a random float in [0,1). Otherwise, returns a random number in [m,n]; m=1 if not given.

View file

@ -10,19 +10,18 @@ local anselme = {
}
package.loaded[...] = anselme
i = require("inspect") -- luacheck: ignore
-- load libs
local preparse = require((...):gsub("anselme$", "parser.preparser"))
local postparse = require((...):gsub("anselme$", "parser.postparser"))
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 identifier_pattern = require((...):gsub("anselme$", "parser.common")).identifier_pattern
local merge_state = require((...):gsub("anselme$", "interpreter.common")).merge_state
local stdfuncs = require((...):gsub("anselme$", "stdlib.functions"))
local bootscript = require((...):gsub("anselme$", "stdlib.bootscript"))
local anselme_root = (...):gsub("anselme$", "")
local preparse = require(anselme_root.."parser.preparser")
local postparse = require(anselme_root.."parser.postparser")
local expression = require(anselme_root.."parser.expression")
local eval = require(anselme_root.."interpreter.expression")
local run_line = require(anselme_root.."interpreter.interpreter").run_line
local to_lua = require(anselme_root.."interpreter.common").to_lua
local identifier_pattern = require(anselme_root.."parser.common").identifier_pattern
local merge_state = require(anselme_root.."interpreter.common").merge_state
local stdfuncs = require(anselme_root.."stdlib.functions")
local bootscript = require(anselme_root.."stdlib.bootscript")
-- wrappers for love.filesystem / luafilesystem
local function list_directory(path)
@ -179,11 +178,13 @@ local vm_mt = {
--- wrapper for loading a whole set of scripts
-- should be preferred to other loading functions if possible
-- requires LÖVE or LuaFileSystem
-- will load in path, in order:
-- * config.ans, which contains various optional configuration options:
-- * alias 👁️: string, default alias for 👁️
-- * alias 🏁: string, default alias for 🏁
-- * alias 🔖: string, default alias for 🔖
-- * language: string, built-in language file to load
-- * main file: string, name (without .ans extension) of a file that will be loaded into the root namespace
-- * main file, if defined in config.ans
-- * every other file in the path and subdirectories, using their path as namespace (i.e., contents of path/world1/john.ans will be defined in a function world1.john)
@ -199,8 +200,14 @@ local vm_mt = {
local checkpoint_alias = self:eval("config.alias 🔖")
local reached_alias = self:eval("config.alias 🏁")
local main_file = self:eval("config.main file")
local language = self:eval("config.language")
-- set aliases
self:setaliases(seen_alias, checkpoint_alias, reached_alias)
-- load language
if language then
local s, e = self:loadlanguage(language)
if not s then return s, e end
end
-- load main file
if main_file then
local s, e = self:loadfile(path.."/"..main_file..".ans")
@ -224,7 +231,7 @@ local vm_mt = {
--- load code
-- similar to Lua's code loading functions.
-- name(default=""): namespace to load the code in. Will define a new function if needed.
-- name(default=""): namespace to load the code in. Will define a new function is specified; otherwise, code will be parsed but not executable from an expression.
-- return self in case of success
-- returns nil, err in case of error
loadstring = function(self, str, name, source)
@ -248,7 +255,7 @@ local vm_mt = {
if not s then return s, err end
return self
end,
loaddirectory = function(self, path, name)
loaddirectory = function(self, path, name) -- requires LÖVE or LuaFileSystem
if not name then name = "" end
name = name == "" and "" or name.."."
for _, item in ipairs(list_directory(path)) do
@ -276,6 +283,18 @@ local vm_mt = {
return self
end,
--- load & execute a built-in language file
-- return self in case of success
-- returns nil, err in case of error
loadlanguage = function(self, lang)
local code = require(anselme_root.."stdlib.languages."..lang)
local s, e = self:loadstring(code, "anselme."..lang, lang)
if not s then return s, e end
s, e = self:eval("anselme."..lang)
if e then return s, e end
return self
end,
--- define functions from Lua
-- signature: full signature of the function
-- fn: function (Lua function or table, see examples in stdlib/functions.lua)
@ -374,7 +393,7 @@ local vm_mt = {
-- expr: expression to evaluate
-- namespace(default=""): namespace to evaluate the expression in
-- tags(default={}): defaults tag when evaluating the expression
-- return value in case of success
-- return value in case of success (nil if nothing returned)
-- returns nil, err in case of error
eval = function(self, expr, namespace, tags)
local interpreter, err = self:run("0", namespace, tags)

View file

@ -30,6 +30,8 @@ Reserved symbols that are still not used as a line type: `^+-=</[]*{}|\_!?.,;)"&
* What does "fqm" means?
It means "fully qualified matriname", which is the same as a fully qualified name, but considers the hierarchy to be mostly mother-daugher based.
It has nothing to do with the fact I'm inept at writing acronyms and realized I wrote it wrong after using it for a whole year.
* Why are built-in anselme scripts stored in Lua files?
I believe it was to avoid reimplementing the require() file search algorithm myself.
* What's a "variant"?
One of the different forms of a same function with a given fqm. No idea why I chose "variant".
* Why emojis?
@ -54,9 +56,6 @@ Disadvantages:
* idk if it's worth the trouble
* could do something like `$ ()(l::list(?), i::number)::?`, but then can't return nil on not found...
TODO: allow to define aliases after the initial definition
~ alias(number, "nombre")
TODO: ensure that most stuff in the state stays consistent after an error was thrown
TODO: way to migrate save files

View file

@ -1,4 +1,4 @@
local truthy, anselme, compare, is_of_type
local truthy, anselme, compare, is_of_type, identifier_pattern, format_identifier
local functions
functions = {
@ -124,6 +124,24 @@ functions = {
return v
end
},
-- alias
["alias(identifier::string, alias::string)"] = {
value = function(identifier, alias)
-- check identifiers
local fqm = identifier:match("^"..identifier_pattern.."$")
if not fqm then error(("%q is not a valid identifier"):format(identifier)) end
fqm = format_identifier(fqm)
local aliasfqm = alias:match("^"..identifier_pattern.."$")
if not aliasfqm then error(("%q is not a valid identifier for an alias"):format(alias)) end
aliasfqm = format_identifier(aliasfqm)
-- define alias
local aliases = anselme.running.state.aliases
if aliases[aliasfqm] ~= nil and aliases[aliasfqm] ~= fqm then
error(("trying to define alias %q for %q, but already exist and refer to %q"):format(aliasfqm, fqm, aliases[alias]))
end
aliases[aliasfqm] = fqm
end
},
-- pair methods
["name(p::pair)"] = {
mode = "untyped raw",
@ -188,7 +206,7 @@ functions = {
},
-- other methods
["error(m::string)"] = function(m) error(m, 0) end,
["rand"] = function() return math.random() end,
["rand()"] = function() return math.random() end,
["rand(a::number)"] = function(a) return math.random(a) end,
["rand(a::number, b::number)"] = function(a, b) return math.random(a, b) end,
["raw(v)"] = {
@ -251,6 +269,8 @@ functions = {
}
package.loaded[...] = functions
local common = require((...):gsub("stdlib%.functions$", "interpreter.common"))
truthy, compare, is_of_type = common.truthy, common.compare, common.is_of_type
local icommon = require((...):gsub("stdlib%.functions$", "interpreter.common"))
truthy, compare, is_of_type = icommon.truthy, icommon.compare, icommon.is_of_type
local pcommon = require((...):gsub("stdlib%.functions$", "parser.common"))
identifier_pattern, format_identifier = pcommon.identifier_pattern, pcommon.format_identifier
anselme = require((...):gsub("stdlib%.functions$", "anselme"))

25
stdlib/languages/frFR.lua Normal file
View file

@ -0,0 +1,25 @@
return [[
(Types)
~ "nil".alias("nul")
~ "number".alias("nombre")
~ "string".alias("texte")
~ "list".alias("liste")
~ "pair".alias("paire")
(Built-in functions)
(~ "alias".alias("alias")
~ "name".alias("nom")
~ "value".alias("valeur")
~ "len".alias("longueur")
~ "insert".alias("ajouter")
~ "remove".alias("retirer")
~ "find".alias("trouver")
~ "error".alias("erreur")
~ "rand".alias("aléa")
~ "raw".alias("brut")
(~ "type".alias("type")
~ "is of type".alias("est de type")
~ "cycle".alias("cycler")
~ "random".alias("aléatoire")
~ "next".alias("séquence")
]]

View file

@ -75,6 +75,9 @@ table.sort(files)
-- test script
if args.script then
local vm = anselme()
if args.lang then
assert(vm:loadlanguage(args.lang))
end
local state, err = vm:loadfile(args.script, "script")
if state then
local istate, e = vm:run("script")