mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-28 00:59:31 +00:00
Translation system first draft
This commit is contained in:
parent
ffadc0dd69
commit
c4636343b4
15 changed files with 215 additions and 18 deletions
|
|
@ -3,7 +3,8 @@ local Identifier, Quote
|
|||
|
||||
local attached_block_identifier, attached_block_symbol
|
||||
|
||||
local AttachBlock = ast.abstract.Node {
|
||||
local AttachBlock
|
||||
AttachBlock = ast.abstract.Node {
|
||||
type = "attach block",
|
||||
|
||||
expression = nil,
|
||||
|
|
@ -38,7 +39,18 @@ local AttachBlock = ast.abstract.Node {
|
|||
state.scope:define(attached_block_symbol, Quote:new(self.block))
|
||||
self.expression:prepare(state)
|
||||
state.scope:pop()
|
||||
end
|
||||
end,
|
||||
|
||||
-- class method: if the block identifier is defined in the current scope, wrap node in an AttachBlock so the block is still defined in this node
|
||||
-- used to preserve the defined _ block without the need to build a full closure
|
||||
-- used e.g. for -> translation, as we want to preserve _ while still executing the translation in the Translatable scope and not restore a different scope from a closure
|
||||
-- (operates on un-evaluated nodes!)
|
||||
preserve = function(self, state, node)
|
||||
if state.scope:defined_in_current(attached_block_symbol) then
|
||||
return AttachBlock:new(node, state.scope:get(attached_block_identifier).expression) -- unwrap Quote as that will be rewrap on eval
|
||||
end
|
||||
return node
|
||||
end,
|
||||
}
|
||||
|
||||
package.loaded[...] = AttachBlock
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ local ResumeParentFunction = ast.abstract.Node {
|
|||
end,
|
||||
|
||||
_eval = function(self, state)
|
||||
if resumable_manager:resuming(state, self) then
|
||||
if self:resuming(state) then
|
||||
self.expression:eval(state)
|
||||
return resumable_manager:get_data(state, self):call(state, ArgumentTuple:new())
|
||||
return self:get_data(state):call(state, ArgumentTuple:new())
|
||||
else
|
||||
resumable_manager:set_data(state, self, resumable_manager:capture(state, 1))
|
||||
self:set_data(state, resumable_manager:capture(state, 1))
|
||||
return self.expression:eval(state)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -112,7 +112,17 @@ Struct = ast.abstract.Runtime {
|
|||
has = function(self, key)
|
||||
local hash = key:hash()
|
||||
return not not self.table[hash]
|
||||
end
|
||||
end,
|
||||
iter = function(self)
|
||||
local t, h = self.table, nil
|
||||
return function()
|
||||
local e
|
||||
h, e = next(t, h)
|
||||
if h == nil then return nil
|
||||
else return e[1], e[2]
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
package.loaded[...] = Struct
|
||||
|
|
|
|||
|
|
@ -58,14 +58,8 @@ Table = ast.abstract.Runtime {
|
|||
return s:has(key)
|
||||
end,
|
||||
iter = function(self, state)
|
||||
local t, h = self.branched:get(state).table, nil
|
||||
return function()
|
||||
local e
|
||||
h, e = next(t, h)
|
||||
if h == nil then return nil
|
||||
else return e[1], e[2]
|
||||
end
|
||||
end
|
||||
local s = self.branched:get(state)
|
||||
return s:iter()
|
||||
end,
|
||||
|
||||
to_struct = function(self, state)
|
||||
|
|
|
|||
49
ast/Translatable.lua
Normal file
49
ast/Translatable.lua
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
local ast = require("ast")
|
||||
local TextInterpolation, String
|
||||
|
||||
local operator_priority = require("common").operator_priority
|
||||
|
||||
local translation_manager
|
||||
|
||||
local Translatable = ast.abstract.Node {
|
||||
type = "translatable",
|
||||
format_priority = operator_priority["%_"],
|
||||
|
||||
expression = nil,
|
||||
|
||||
init = function(self, expression)
|
||||
self.expression = expression
|
||||
self.context = ast.Struct:new()
|
||||
self.context:set(String:new("source"), String:new(self.expression.source))
|
||||
if TextInterpolation:is(self.expression) then
|
||||
self.format_priority = expression.format_priority
|
||||
end
|
||||
end,
|
||||
|
||||
_format = function(self, ...)
|
||||
if TextInterpolation:is(self.expression) then -- wrapped in translatable by default
|
||||
return self.expression:format(...)
|
||||
else
|
||||
return "%"..self.expression:format_right(...)
|
||||
end
|
||||
end,
|
||||
|
||||
traverse = function(self, fn, ...)
|
||||
fn(self.expression, ...)
|
||||
end,
|
||||
|
||||
_eval = function(self, state)
|
||||
return translation_manager:eval(state, self.context, self)
|
||||
end,
|
||||
|
||||
list_translatable = function(self, t)
|
||||
table.insert(t, self)
|
||||
end
|
||||
}
|
||||
|
||||
package.loaded[...] = Translatable
|
||||
TextInterpolation, String = ast.TextInterpolation, ast.String
|
||||
|
||||
translation_manager = require("state.translation_manager")
|
||||
|
||||
return Translatable
|
||||
|
|
@ -44,6 +44,9 @@ traverse = {
|
|||
end,
|
||||
hash = function(self, t)
|
||||
table.insert(t, self:hash())
|
||||
end,
|
||||
list_translatable = function(self, t)
|
||||
self:list_translatable(t)
|
||||
end
|
||||
}
|
||||
|
||||
|
|
@ -119,6 +122,15 @@ Node = class {
|
|||
self:traverse(traverse.prepare, state)
|
||||
end,
|
||||
|
||||
-- generate a list of translatable nodes that appear in this node
|
||||
-- should only be called on non-runtime nodes
|
||||
-- if a node is translatable, redefine this to add it to the table - note that it shouldn't call :traverse or :list_translatable on its children, as nested translations should not be needed
|
||||
list_translatable = function(self, t)
|
||||
t = t or {}
|
||||
self:traverse(traverse.list_translatable, t)
|
||||
return t
|
||||
end,
|
||||
|
||||
-- same as eval, but make the evaluated expression as a resume boundary
|
||||
-- i.e. if a checkpoint is defined somewhere in this eval, it will start back from this node eval when resuming
|
||||
eval_resumable = function(self, state)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue