add basic macro expansion
This commit is contained in:
parent
f010267f11
commit
38a752be5a
6 changed files with 150 additions and 25 deletions
|
@ -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"
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
@foo
|
||||
{@foo|@bar|12\|}
|
||||
|
||||
|
||||
|
|
13
src/classes.jl
Normal file
13
src/classes.jl
Normal file
|
@ -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
|
118
src/parsing.jl
118
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
|
29
src/passes.jl
Normal file
29
src/passes.jl
Normal file
|
@ -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
|
10
src/uahgi.jl
10
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
|
||||
|
|
Loading…
Reference in a new issue