create basic modification of arranger
Some checks are pending
CI / Julia 1.6 - ubuntu-latest - x64 (push) Waiting to run
CI / Julia 1.7 - ubuntu-latest - x64 (push) Waiting to run
CI / Julia pre - ubuntu-latest - x64 (push) Waiting to run

This commit is contained in:
Tan, Kian-ting 2025-01-30 00:39:34 +08:00
parent eb3f1967aa
commit 27d66b0e51
7 changed files with 248 additions and 59 deletions

View file

@ -1,8 +1,7 @@
{@lang|en}
{@def|@font|{@quote|FreeSans|AR PL UKai TW}}
{@def|@fontsize|12}
therapy of communication and pronounciation123%comment
anotherline%{@set|@fontsize|10} processing
of the problem
{@def|@linewidth|200} %in px%
{@def|@spacing|{@hglue|{@ex|1}|2}}
{@def|@cjk_spacing|{@hglue|{@ex|0}|0.001}}
11111 222 3333333 444444 555555 666666 77777 88888 99999 000000 11111 22222 33333 55555

11
example/ex2.ug Normal file
View file

@ -0,0 +1,11 @@
{@lang|en}
{@def|@font|{@quote|FreeSans|AR PL UKai TW}}
{@def|@fontsize|12}
{@def|@linewidth|300} %in px%
{@def|@spacing|{@hglue|{@ex|1}|2}}
{@def|@cjk_spacing|{@hglue|{@ex|0}|0.001}}
therapy of communication and pronounciation123%comment
anotherline%{@set|@fontsize|10} processing of
of the problem

37
src/arrange.jl Normal file
View file

@ -0,0 +1,37 @@
module Arrange
using Match
u = Main.uahgi
# the cost of make ith to jth char a line
function cost(items, i, j, linewidth)
slice = items[i:j]
cost_list = map(x -> item_cost(x), slice)
sum_of_cost_list = reduce((x, y)-> x+y, cost_list)
if sum_of_cost_list > linewidth
return Inf
else
return linewidth - sum_of_cost_list
end
end
function item_cost(i)
if typeof(i) == u.HGlue
return i.wd
elseif typeof(i) == u.ChBox
return i.wd
else
return 0
end
end
function arrange(vbox, env)
result_vbox_inner = []
linewidth = parse(Int, env["linewidth"])
print(cost(vbox.eles[1].eles, 1, 20, linewidth))
return vbox
end
end

View file

@ -8,6 +8,12 @@ using .PDFOperating
u = Main.uahgi
c = Main.uahgi.Parsing.Passes.Classes
@enum PutChar begin
true_ = 0
false_ = 1
gen_chbox_ = 2
end
function interp_main(ast, env, res_box)
ast_inner = ast.val
val = nothing
@ -22,17 +28,33 @@ interp: the intepreter of the uahgi.
- ast: element or part of the ast
- env: the variable storaging environment
- res_box: the generated result box containing the content\
- put_char(bool. value): if the character should be put into the res_box
- put_char(PutChar): if the character should be put into the res_box.
"""
function interp(ast, env, res_box, put_char=true)
function interp(ast, env, res_box, put_char=true_)
#println("INTERP", ast)
@match ast begin
c.SEQ([c.ELE([c.ID("def")]),
c.ELE([c.ID(id)]),val]) =>
begin
(val_evaled, env, res_box) = interp(val, env, res_box, false)
(val_evaled, env, res_box) = interp(val, env, res_box, false_)
#println("ID~~~", id, " VAL~~~", val_evaled)
if !haskey(env, id)
env[id] = val_evaled
else
throw("the variable $id has been defined.")
end
return (val_evaled, env, res_box)
end
c.SEQ([c.ELE([c.ID("set")]),
c.ELE([c.ID(id)]),val]) =>
begin
(val_evaled, env, res_box) = interp(val, env, res_box, false_)
#println("ID~~~", id, " VAL~~~", val_evaled)
if haskey(env, id)
env[id] = val_evaled
else
throw("the variable $id is not defined yet.")
end
return (val_evaled, env, res_box)
end
c.SEQ([c.ELE([c.ID("quote")]),
@ -45,49 +67,107 @@ function interp(ast, env, res_box, put_char=true)
c.ELE([v...]) => begin
ele = reduce( (x, y) -> x*""*y,
map(i -> interp(i, env, res_box, false)[1], v))
map(i -> interp(i, env, res_box, false_)[1], v))
return (ele, env, res_box)
end
c.SEQ([c.ELE([c.ID("par")])]) =>begin
push!(res_box.eles, u.HBox([],
nothing, nothing, nothing, nothing, nothing))
return (ast, env, res_box)
end
c.SEQ([c.ELE([c.ID("ex")]), val]) =>begin
x = 'x'
font_family = select_font(x, env)
font_path = get_font_path(font_family)
font_size = parse(Int, env["fontsize"])
charmetrics = PDFOperating.check_char_size(
'x',
font_path,
font_size)
ex_in_px = charmetrics.wd
(val, _, _) = interp(val, env, res_box, false_)
val_ex_in_px = ex_in_px * parse(Int,val)
return (val_ex_in_px, env, res_box)
end
c.SEQ([c.ELE([c.ID("hglue")]),
width,stretch]) => begin
if put_char == true_
(width_evaled, _, _) = interp(width, env, res_box, false_)
(stretch_evaled, _, _) = interp(stretch, env, res_box, false_)
push!(res_box.eles[end].eles,
u.HGlue(width_evaled, parse(Int, stretch_evaled))
)
end
return (ast, env, res_box)
end
c.CHAR(ch) => begin
atomic_ch = ch[1]
if put_char == true
font_idx = 1
font_family = string(env["font"][font_idx])
font_family_length = length(font_family)
while !is_in_font(atomic_ch, font_family)
if font_idx <= font_family_length
font_idx += 1
font_family = string(env["font"][font_idx])
else
font_list = string(env["font"])
throw("the chars $atomic_ch is not contained in all the fonts
listed in listed fonts: $font_list")
end
if put_char == false_
return (ch, env, res_box)
end
font_family = select_font(atomic_ch, env)
font_path = get_font_path(font_family)
font_size = parse(Int, env["fontsize"])
glyph_metrics = PDFOperating.check_char_size(
atomic_ch, font_path, font_size)
push!(res_box.eles[end].eles,
u.ChBox(ch,
chbox = u.ChBox(ch,
font_path,
font_size,
glyph_metrics.ht,
glyph_metrics.dp,
glyph_metrics.wd))
end
return (ch, env, res_box)
end
c.NL(nl) => return (nl, env, res_box)
c.SPACE(sp) => return (sp, env, res_box)
glyph_metrics.wd,
nothing, nothing)
if put_char == true_
push!(res_box.eles[end].eles, chbox)
return (ch, env, res_box)
else # put_char == gen_chbox_
return (chbox, env, res_box)
end
end
c.SEQ([c.ELE([c.ID("disc")]),
c.ELE(before),
c.ELE(after),
c.ELE(orig)])=> begin
before_item = length(before) == 0 ? [] : before[1]
after_item = length(after) == 0 ? [] : after[1]
orig_item = length(orig) == 0 ? [] : orig[1]
(before_evaled, _, _) = interp(before_item, env, res_box, gen_chbox_)
(after_evaled, _, _) = interp(after_item, env, res_box, gen_chbox_)
(orig_evaled, _, _) = interp(orig_item, env, res_box, gen_chbox_)
ret = u.Disc(before_evaled, after_evaled, orig_evaled)
println("RETURN", ret)
push!(res_box.eles[end].eles, ret)
return (ret, env, res_box)
end
c.NL(nl) => begin
#if spacing defined
if haskey(env, "spacing")
(spacing, _, _) = interp(env["spacing"], env, res_box, false_)
add_spacing = interp(spacing, env, res_box, true_)
end
return (nl, env, res_box)
end
c.SPACE(sp) => begin
#if spacing defined
if haskey(env, "spacing")
(spacing, _, _) = interp(env["spacing"], env, res_box, false_)
add_spacing = interp(spacing, env, res_box, true_)
end
return (sp, env, res_box)
end
# empty item
[] => return (ast, env, res_box)
_ => begin
println("不知道")
val_evaled = "不知道"
@ -144,6 +224,24 @@ function padding_zero(i)
return i
end
"""
Select proper font having the glyph of char `ch`
"""
function select_font(ch, env)
font_idx = 1
font_family = string(env["font"][font_idx])
font_family_length = length(font_family)
while !is_in_font(ch, font_family)
if font_idx <= font_family_length
font_idx += 1
font_family = string(env["font"][font_idx])
else
font_list = string(env["font"])
throw("the chars $atomic_ch is not contained in all the fonts
listed in listed fonts: $font_list")
end
end
return font_family
end
end

View file

@ -15,7 +15,7 @@ grammar rules of uahgi
comment = P"\%[^%]+\%"
newline = P"(\r?\n)" |> Passes.Classes.NL
space = p"[ \t]" > Passes.Classes.SPACE
space = p"[ \t]+" > Passes.Classes.SPACE
id_name = p"[_a-zA-Z][_0-9a-zA-Z]*" > Passes.Classes.ID
id = E"@" + id_name
@ -139,10 +139,4 @@ function ast_to_string(ast)
return str
end
# Write your package code here.
#export cat
#cat = 1.2
end

View file

@ -26,8 +26,7 @@ push!(processed_passes, two_nl_to_par_pass)
# in 2 hanzi add glue.
function insert_hglue_in_adjacent_chinese(two_nl)
_0pt = Classes.SEQ([Classes.ID("pt"); Classes.CHAR(["0"])])
inner = Classes.SEQ([Classes.ID("hglue"); _0pt])
inner = Classes.ID("cjk_spacing")
return [two_nl[1]; inner; two_nl[2]]
end
adjacent_chinese_pattern = [Classes.CHAR(r"[\p{Han},。!?:「」『』…]"),

View file

@ -1,11 +1,28 @@
module uahgi
include("parsing.jl")
include("interp.jl")
include("arrange.jl")
using .Interp
using .Parsing
using .Arrange
using ArgParse
export ChBox, HGlue
abstract type Box end
"""
a like-breakable discrete point.
- before: the item before likebreaking
- after: the item after linebreaking
- orig: the status while not triggering like breaking
"""
mutable struct Disc<:Box
before
after
orig
end
"""
Horizonal Box
@ -19,8 +36,21 @@ mutable struct HBox<:Box
ht
dp
wd
x
y
end
"""
Horizonal Glue (HGlue)
- wd: width
- str : stretch
"""
mutable struct HGlue<:Box
wd
str
end
"""
Vertical Box
@ -34,6 +64,8 @@ mutable struct VBox<:Box
ht
dp
wd
x
y
end
"""
@ -53,6 +85,8 @@ mutable struct ChBox<:Box
ht
dp
wd
x
y
end
function parse_commandline()
@ -64,7 +98,7 @@ function parse_commandline()
@add_arg_table! s begin
"FILE"
help = "the file path to be converted."
required = true
required = false
end
return parse_args(s)
@ -74,6 +108,18 @@ end
function main()
parsed_args = parse_commandline()
file_path = parsed_args["FILE"]
if file_path === nothing
#help string
help = "usage: uahgi.jl [-h] [FILE]
positional arguments:
FILE the file path to be converted.
optional arguments:
-h, --help show this help message and exit"
println(help)
return 0
end
# for test
#if parsed_args["FILE"] === nothing
# file_path = "./example/ex1.ug"
@ -85,11 +131,16 @@ function main()
default_env = Dict() # the default environment for the intepreter
output_box_orig = VBox([HBox([], nothing, nothing, nothing)],
nothing, nothing, nothing)
output_box_orig = VBox([HBox([], nothing, nothing, nothing, nothing, nothing)],
nothing, nothing, nothing, nothing, nothing)
output_box_result = Interp.interp_main(ast, default_env, output_box_orig)
print("Env", output_box_result[2])
print("OutPutBox", output_box_result[3])
env = output_box_result[2]
output_box = output_box_result[3]
print(output_box)
#TODO
arranged = Arrange.arrange(output_box, env)
end