Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Idea: use MacroTools.jl? #149

Closed
alhirzel opened this issue Nov 21, 2020 · 4 comments
Closed

Idea: use MacroTools.jl? #149

alhirzel opened this issue Nov 21, 2020 · 4 comments
Labels
wontfix This will not be worked on

Comments

@alhirzel
Copy link
Contributor

I know at this point it could be a heroic effort, but after looking at the parser for @aml, I thought it would be appropriate to suggest usage of MacroTools.jl and their @capture macro. It might be the biggest help around here:

########################
# Single struct name - "aml name"
if isa(ei, String)
# struct_function[1]=missing # function
# Self-name checker
if ei == "~"
if T isa Symbol
struct_name = string(T)
elseif T isa Expr && T.head == :curly
struct_name = string(T.args[1]) # S
end
else
struct_name = ei # Type aml name
end
argsexpr.args[i] = nothing # removing "aml name" from expr args
struct_nodetype = AbsNormal
################################################################
# Literal Struct name - empty"aml name"
elseif isa(ei, Tuple)
################################################################
# Struct aml
########################
# Literal only empty"aml name"
if isa(ei, Tuple{Type,String})
# struct_function[1]=missing # function
# Self-name checker
if ei[2] == "~"
if T isa Symbol
struct_name = string(T)
elseif T isa Expr && T.head == :curly
struct_name = string(T.args[1]) # S
end
else
struct_name = ei[2] # Type aml name
end
struct_nodetype = ei[1]
struct_nodetype = aml_dispatch(struct_nodetype, struct_name)
argsexpr.args[i] = nothing # removing "aml name" from expr args
# Custom Code
elseif isa(ei, Tuple{Symbol, Expr})
iMacro += 1
# Row for code insertion (insert before iArg-th argument)
if ei[1] == :creator
args_custom_creator[iArg] = ei[2]
elseif ei[1] == :extractor
args_custom_extractor[iArg] = ei[2]
elseif ei[1] == :updater
args_custom_updater[iArg] = ei[2]
end
argsexpr.args[i] = nothing # removing custom code macro from expr args
end
elseif ei isa Expr && ei.head == :tuple
########################
# Struct Function - "aml name", F
if isa(ei.args[1], String) && isa(ei.args[2], Union{Symbol,Function}) # "aml name", F
struct_function[1]=ei.args[2] # function
# Self-name checker
if ei.args[1] == "~"
if T isa Symbol
struct_name = string(T)
elseif T isa Expr && T.head == :curly
struct_name = string(T.args[1]) # S
end
else
struct_name = ei.args[1] # Type aml name
end
struct_nodetype = AbsNormal
argsexpr.args[i] = nothing # removing "aml name" from expr args
########################
# Literal and Struct Function - empty"aml name", F
elseif isa(ei.args[1], Tuple) && isa(ei.args[2], Union{Symbol,Function})
struct_function[1]=ei.args[2] # function
# Self-name checker
if ei.args[1][2] == "~"
if T isa Symbol
struct_name = string(T)
elseif T isa Expr && T.head == :curly
struct_name = string(T.args[1]) # S
end
else
struct_name = ei.args[1][2] # Type aml name
end
struct_nodetype = ei.args[1][1]
struct_nodetype = aml_dispatch(struct_nodetype, struct_name)
argsexpr.args[i] = nothing # removing "aml name" from expr args
################################################################
# Arguments
########################
# No Def Value
elseif ei.args[1] isa Union{Symbol,Expr} # var/var::T, "name"
# Def Value
# args_defaultvalue[iArg] = missing
# Type Checker
lhs = ei.args[1]
if lhs isa Symbol # var, "name"
var = ei.args[1]
args_type[iArg] = String # consider String as the type
args_param[iArg] = var
args_var[iArg] = var
argsexpr.args[i] = var # removing "name",...
elseif lhs isa Expr && lhs.head == :(::) && lhs.args[1] isa Symbol # var::T, "name"
var = lhs.args[1]
varType = lhs.args[2] # Type
args_type[iArg] = varType
args_param[iArg] = var
args_var[iArg] = var
argsexpr.args[i] = lhs # removing "name",...
end
# Literal Checker
if length(ei.args[2]) == 2 # literal
argAmlType = ei.args[2][1]
args_literaltype[iArg] = argAmlType # literal type
ni = ei.args[2][2]
# Self-name checker
if ni == "~"
args_name[iArg] = string(var)
else
args_name[iArg] = ni
end
else
args_literaltype[iArg] = AbsNormal # non-literal
ni = ei.args[2]
# Self-name checker
if ni == "~"
args_name[iArg] = string(var)
else
args_name[iArg] = ni
end
end
# Function Checker
if length(ei.args) == 3 && isa(ei.args[3], Union{Function, Symbol}) # var/var::T, "name", f
fun = ei.args[3] # function
args_function[iArg] = fun
# else # function name isn't given
# args_function[iArg] = missing
end
end # end Tuple sub possibilities
################################################################
# Def Value
elseif ei isa Expr && ei.head == :(=) # def value provided
# aml name Checker
if ei.args[2] isa Expr && ei.args[2].head == :tuple # var/var::T = defVal, "name"
# Def Value
defVal = ei.args[2].args[1]
args_defaultvalue[iArg] = defVal
lhs = ei.args[1]
argsexpr.args[i] = lhs # remove =defVal for type definition
# Type Checker
if lhs isa Symbol # var = defVal, "name"
var = ei.args[1]
args_type[iArg] = String # consider String as the type
args_param[iArg] = Expr(:kw, var, defVal)
args_var[iArg] = var
argsexpr.args[i] = var # removing "name",...
elseif lhs isa Expr && lhs.head == :(::) && lhs.args[1] isa Symbol # var::T = defVal, "name"
var = lhs.args[1]
varType = lhs.args[2] # Type
args_type[iArg] = varType
args_param[iArg] = Expr(:kw, var, defVal) # TODO also put type expression
args_var[iArg] = var
argsexpr.args[i] = lhs # removing "name",...
end
# Literal Checker
if length(ei.args[2].args[2]) == 2 # literal
argAmlType = ei.args[2].args[2][1]
args_literaltype[iArg] = argAmlType # literal type
ni = ei.args[2].args[2][2]
# Self-name checker
if ni == "~"
args_name[iArg] = string(var)
else
args_name[iArg] = ni
end
else
args_literaltype[iArg] = AbsNormal # non-literal
ni = ei.args[2].args[2]
# Self-name checker
if ni == "~"
args_name[iArg] = string(var)
else
args_name[iArg] = ni
end
end
# Function Checker
if length(ei.args[2].args) == 3 && isa(ei.args[2].args[3], Union{Function, Symbol}) # var/var::T = defVal, "name", f
fun = ei.args[2].args[3] # function
args_function[iArg] = fun
# else # function name isn't given
# args_function[iArg] = missing
end
########################
# No aml Name - But defVal
else # var/var::T = defVal # ignored for creating aml
# Type Checker
lhs = ei.args[1]
if lhs isa Symbol # var = defVal
defVal = ei.args[2]
args_defaultvalue[iArg] = defVal
# args_name[iArg] = missing # ignored for creating aml
# args_function[iArg] = missing # ignored for creating aml
var = ei.args[1]
args_type[iArg] = Any
args_param[iArg] = Expr(:kw, var, defVal)
args_var[iArg] = var
argsexpr.args[i] = var # remove =defVal for type definition
elseif lhs isa Expr && lhs.head == :(::) && lhs.args[1] isa Symbol # var::T = defVal
defVal = ei.args[2]
args_defaultvalue[iArg] = defVal
# args_name[iArg] = missing # ignored for creating aml
# args_function[iArg] = missing # ignored for creating aml
var = lhs.args[1]
varType = lhs.args[2] # Type
args_type[iArg] = varType
args_param[iArg] = Expr(:kw, var, defVal) # TODO also put type expression
args_var[iArg] = var
argsexpr.args[i] = lhs # remove =defVal for type definition
else
# something else, e.g. inline inner constructor
# F(...) = ...
continue
end
end
################################################################
# No aml name - No defVal
else # var/var::T # ignored for creating aml
# Type Checker
if ei isa Symbol # var
# args_name[iArg] = missing # argument ignored for aml
# args_function[iArg] = missing # ignored for creating aml
args_type[iArg] = String
var = ei
args_param[iArg] = var
args_var[iArg] = var
elseif ei.head == :(::) && ei.args[1] isa Symbol # var::T
# args_name[iArg] = missing # argument ignored for aml
# args_function[iArg] = missing # ignored for creating aml
var = ei.args[1]
varType = ei.args[2] # Type
args_type[iArg] = varType
args_param[iArg] = var
args_var[iArg] = var
elseif ei.head == :block # anything else should be evaluated again
# can arise with use of @static inside type decl
argsexpr, args_param, args_defaultvalue, args_type, args_var, args_name, args_function, args_literaltype, struct_name, struct_nodetype, struct_function, is_struct_mutable, args_custom_creator, args_custom_extractor, args_custom_updater, T = aml_parse(expr)
else
continue
end

@aminya
Copy link
Owner

aminya commented Nov 21, 2020

The code is @aml_parse works without any issues. I have written the parsing code manually by hand which, in addition to being correct, is much more performant than using a @capture macro which has limited functionality.

Once, I tried to add something to MacroTools, but it never got through. I am not interested in adding a dependency for a project that is impossible to update.
FluxML/MacroTools.jl#136

@aminya aminya closed this as completed Nov 21, 2020
@aminya aminya added wontfix This will not be worked on and removed feature_request labels Nov 21, 2020
Repository owner deleted a comment from issue-label-bot bot Nov 21, 2020
@alhirzel
Copy link
Contributor Author

Aha, I should have done a better search! Thank you for the background and reasoning.

@aminya
Copy link
Owner

aminya commented Nov 21, 2020

You're welcome. A simplified version of this parsing code exist at https://github.com/aminya/VarStructs.jl/blob/master/src/parse.jl

I might be able to refactor varTdefVal and varT in this repository, in the future if I found time.

GitHub
Variable Julia Structs with dispatching. Contribute to aminya/VarStructs.jl development by creating an account on GitHub.

@alhirzel
Copy link
Contributor Author

That's an interesting package that I had not yet seen, thank you for the pointer!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants