uahgi/src/parsing.jl

130 lines
3.3 KiB
Julia
Raw Normal View History

2025-01-21 23:46:40 +08:00
module Parsing
using ParserCombinator
2025-01-25 02:23:13 +08:00
using Match
include("passes.jl")
using .Passes
2025-01-21 23:46:40 +08:00
#=
grammar rules of uahgi
=#
2025-01-25 02:23:13 +08:00
comment = P"\%[^%]+\%"
newline = P"(\r?\n)" |> Passes.Classes.NL
space = p"[ \t]" > Passes.Classes.SPACE
2025-01-21 23:46:40 +08:00
2025-01-25 02:23:13 +08:00
id_name = p"[_a-zA-Z][_0-9a-zA-Z]*" > Passes.Classes.ID
2025-01-21 23:46:40 +08:00
id = E"@" + id_name
2025-01-25 02:23:13 +08:00
char = p"[^ \n\r\t\\]" |> Passes.Classes.CHAR #[1:2,:?]
2025-01-21 23:46:40 +08:00
# chars should be preceded by "\" are \, {, }, |, @, %
2025-01-25 02:23:13 +08:00
esc_char = p"[\{\|\}\@\%]" > Passes.Classes.ESC_CHAR
2025-01-21 23:46:40 +08:00
esc_combined = E"\\" + esc_char
#=
seq = (foo x1 x2 " ")
=> {@foo|x1|x2| }
=#
char_and_combined = char | esc_combined
2025-01-25 02:23:13 +08:00
seq_item = id | Repeat(char_and_combined) |> Passes.Classes.ELE
2025-01-21 23:46:40 +08:00
seq_item_rest = E"|" + seq_item
2025-01-25 02:23:13 +08:00
seq_inner = seq_item + (seq_item_rest)[0:end] |> Passes.Classes.SEQ
2025-01-21 23:46:40 +08:00
seq = E"{" + seq_inner + E"}"
part = seq | comment | space | newline | id | char
2025-01-25 02:23:13 +08:00
all = (Repeat(part) + Eos()) |> Passes.Classes.PROG
2025-01-21 23:46:40 +08:00
function parse(input)
print(input)
2025-01-25 02:23:13 +08:00
ast = parse_one(input, all)[1]
print("\n" * string(ast) * "\n")
2025-01-21 23:46:40 +08:00
#print(parse_one(, Pattern(r".b.")))
2025-01-25 02:23:13 +08:00
passes = Passes.processed_passes
ast_val = ast.val
for pass in passes
ast_val = use_pass(ast_val, pass)
end
new_ast = Passes.Classes.PROG(ast_val)
print(ast_to_string(new_ast))
return ast
end
function ast_pattern_matched(pattern, ast_head)
zipped = zip(pattern, ast_head)
zipped_mapped = map(x -> match_unit(x), zipped)
is_all_matched = reduce((x,y)-> x && y, zipped_mapped)
return is_all_matched
end
function match_unit(pair)
pattern = pair[1]
ast_item = pair[2]
if typeof(pattern) == Passes.Classes.PTN_RGX
is_matched = match(pattern.val, ast_item.val)
return is_matched
else
return pattern.val == ast_item.val
end
end
function use_pass(ast_val, pass)
pass_pattern = pass.pattern
pass_pattern_length = length(pass_pattern)
if length(ast_val) < pass_pattern_length
return ast_val
else
ast_head = ast_val[1:pass_pattern_length]
if ast_pattern_matched(pass_pattern, ast_head)
ast_head = pass.func(ast_head)
remained = use_pass([ast_head[2:end];ast_val[pass_pattern_length+1:end]], pass)
ast_val = [ast_head[1]; remained]
else
return ast_val
end
end
2025-01-21 23:46:40 +08:00
end
2025-01-25 02:23:13 +08:00
function ast_to_string(ast)
item = 5
str = @match ast begin
Passes.Classes.PROG(v) => begin
prog_inner = reduce( (x, y) -> x*" "*y, map(i -> ast_to_string(i), v))
return "[" * prog_inner * "]"
end
Passes.Classes.SEQ(v) => begin
prog_inner = reduce( (x, y) -> x*" "*y, map(i -> ast_to_string(i), v))
return "(" * prog_inner * ")"
end
Passes.Classes.ID(v) => "[ID: " * v * "]"
Passes.Classes.ELE(v) => begin
prog_inner = reduce( (x, y) -> x*" "*y, map(i -> ast_to_string(i), v))
return "[ELE : (" * prog_inner * ")]"
end
Passes.Classes.ESC_CHAR(ch) => "[ESC:\"" * ch[1] * "\"]"
Passes.Classes.CHAR(ch) => "\"" * ch[1] * "\""
Passes.Classes.NL(_) => "NL"
Passes.Classes.SPACE(_) => "SPACE"
_ => string(ast)
end
return str
end
2025-01-21 23:46:40 +08:00
# Write your package code here.
2025-01-25 02:23:13 +08:00
#export cat
2025-01-21 23:46:40 +08:00
2025-01-25 02:23:13 +08:00
#cat = 1.2
2025-01-21 23:46:40 +08:00
end