From 38a752be5a4a27c710476d7c1f783becf0828e2f Mon Sep 17 00:00:00 2001 From: Tan Kian-ting Date: Sat, 25 Jan 2025 02:23:13 +0800 Subject: [PATCH] add basic macro expansion --- Project.toml | 1 + example/ex1.ug | 4 +- src/classes.jl | 13 ++++++ src/parsing.jl | 118 ++++++++++++++++++++++++++++++++++++++++--------- src/passes.jl | 29 ++++++++++++ src/uahgi.jl | 10 +++-- 6 files changed, 150 insertions(+), 25 deletions(-) create mode 100644 src/classes.jl create mode 100644 src/passes.jl diff --git a/Project.toml b/Project.toml index 9d4a457..9f798a1 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "1.0.0-DEV" [deps] ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" +Match = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf" ParserCombinator = "fae87a5f-d1ad-5cf0-8f61-c941e1580b46" libharu_jll = "d4e8948d-4b7e-5538-9d15-404f6f0a9070" diff --git a/example/ex1.ug b/example/ex1.ug index a8c2978..139597f 100644 --- a/example/ex1.ug +++ b/example/ex1.ug @@ -1,2 +1,2 @@ -@foo -{@foo|@bar|12\|} \ No newline at end of file + + diff --git a/src/classes.jl b/src/classes.jl new file mode 100644 index 0000000..0d09350 --- /dev/null +++ b/src/classes.jl @@ -0,0 +1,13 @@ +module Classes +abstract type Node end +struct ID<:Node val end +struct SEQ<:Node val end # like (a b c) in scheme +struct ELE<:Node val end #an element in a seq +struct ESC_CHAR<:Node val end # character preceded by escape char "\" +struct CHAR<:Node val end #character +struct SPACE<:Node val end # space +struct NL<:Node val end # newline +struct PROG<:Node val end # all the program +# pattern in regex form +struct PTN_RGX<:Node val::Regex end +end \ No newline at end of file diff --git a/src/parsing.jl b/src/parsing.jl index 534e124..5f8c749 100644 --- a/src/parsing.jl +++ b/src/parsing.jl @@ -1,52 +1,130 @@ module Parsing using ParserCombinator -abstract type Node end -struct ID<:Node val end -struct SEQ<:Node val end # like (a b c) in scheme -struct ELE<:Node val end #an element in a seq -struct ESC_CHAR<:Node val end # character preceded by escape char "\" +using Match + +include("passes.jl") +using .Passes #= grammar rules of uahgi =# -comment = p"\%[^%]+\%" -newline = p"(\r?\n)" -space = p"[ \t]" +comment = P"\%[^%]+\%" +newline = P"(\r?\n)" |> Passes.Classes.NL +space = p"[ \t]" > Passes.Classes.SPACE -id_name = p"[_a-zA-Z][_0-9a-zA-Z]*" > ID +id_name = p"[_a-zA-Z][_0-9a-zA-Z]*" > Passes.Classes.ID id = E"@" + id_name -char = p"[^ \n\r\t\\]"#[1:2,:?] +char = p"[^ \n\r\t\\]" |> Passes.Classes.CHAR #[1:2,:?] # chars should be preceded by "\" are \, {, }, |, @, % -esc_char = p"[\{\|\}\@\%]" > ESC_CHAR +esc_char = p"[\{\|\}\@\%]" > Passes.Classes.ESC_CHAR esc_combined = E"\\" + esc_char #= seq = (foo x1 x2 " ") => {@foo|x1|x2| } =# char_and_combined = char | esc_combined -seq_item = id | Repeat(char_and_combined) |> ELE +seq_item = id | Repeat(char_and_combined) |> Passes.Classes.ELE seq_item_rest = E"|" + seq_item -seq_inner = seq_item + (seq_item_rest)[0:end] |> SEQ +seq_inner = seq_item + (seq_item_rest)[0:end] |> Passes.Classes.SEQ seq = E"{" + seq_inner + E"}" part = seq | comment | space | newline | id | char -all = Repeat(part) + Eos() +all = (Repeat(part) + Eos()) |> Passes.Classes.PROG function parse(input) print(input) - b = parse_one(input, all) - print("\n" * string(b) * "\n") + ast = parse_one(input, all)[1] + print("\n" * string(ast) * "\n") + #print(parse_one(, Pattern(r".b."))) -end -# Write your package code here. -#export dog + + passes = Passes.processed_passes -#dog = 1.2 + + 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 +end + +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 + +# Write your package code here. +#export cat + +#cat = 1.2 end \ No newline at end of file diff --git a/src/passes.jl b/src/passes.jl new file mode 100644 index 0000000..dfe254d --- /dev/null +++ b/src/passes.jl @@ -0,0 +1,29 @@ + +module Passes +include("classes.jl") +using .Classes + +export processed_passes, Pass +processed_passes = [] + +struct Pass + pattern + func +end + +####definition of passes #### + +# 2 newline become @par{} +function two_nl_to_par_pass_func(two_nl) + return [Classes.SEQ([Classes.ID("par")])] +end +two_nl_to_par_pattern = [Classes.NL([]), Classes.NL([])] #two continuous newline + + +two_nl_to_par_pass = Pass(two_nl_to_par_pattern, + two_nl_to_par_pass_func) + + +push!(processed_passes, two_nl_to_par_pass) + +end \ No newline at end of file diff --git a/src/uahgi.jl b/src/uahgi.jl index 08a57bf..d988340 100644 --- a/src/uahgi.jl +++ b/src/uahgi.jl @@ -1,5 +1,5 @@ module uahgi -include("./parsing.jl") +include("parsing.jl") using .Parsing using ArgParse @@ -12,7 +12,7 @@ function parse_commandline() @add_arg_table! s begin "FILE" help = "the file path to be converted." - required = true + #required = true end return parse_args(s) @@ -21,7 +21,11 @@ end function main() parsed_args = parse_commandline() - file_path = parsed_args["FILE"] + if parsed_args["FILE"] === nothing + file_path = "./example/ex1.ug" # for test + else + file_path = parsed_args["FILE"] + end file_content = open(f->read(f, String), file_path) Parsing.parse(file_content) end