#import "uml.typ" #let parse-args(data) = { let args = data.split(",").map(a => a.trim()).filter(a => a.len() != 0) let res if ":" in data { res = (:) } else { res = () } for arg in args { let parts = arg.split(":") let arg-name = none let arg-type if parts.len() == 1 { if type(res) == dictionary { panic("Cannot mix named and unnamed arguments") } arg-type = parts.first().trim() res.push(arg-type) } else { arg-name = parts.first().trim() arg-type = parts.slice(1).join(":").trim() res.insert(arg-name, arg-type) } } return res } #let parse(data) = { let elements = () if type(data) == raw or type(data) == content { data = data.text } let classes = data.matches(regex("(?ms)(abstract class|class|interface) (.*?)\s*\{(.*?)\}")) for class in classes { let family-name = class.captures.first() let family = ( class: none, "abstract class": uml.abstract, "interface": uml.interface, "enum": uml.enum, ).at(family-name) let name = class.captures.at(1) let class-data = class.captures.last().trim() let members = class-data.matches(regex("(?m)^\s*(.*?)\s*(:\s*([^:]*?))?$")).filter(m => m.text.len() != 0) let attributes = () let methods = () for member in members { let member-name = member.captures.first() let val-type = member.captures.last() let visibility = none if member-name.starts-with(regex("\+|-|~|#")) { let vis = member-name.first() member-name = member-name.slice(1) visibility = ( "+": uml.public, "-": uml.private, "~": uml.package, "#": uml.protected ).at(vis) } if member-name.ends-with(")") { let func = member-name.match(regex("^(.*?)\((.*)\)$")) member-name = func.captures.first() let args = parse-args(func.captures.last()) methods += uml.method(member-name, visibility, val-type, args) } else { attributes += uml.attr(member-name, visibility, val-type) } } elements += uml.class(name, family, attributes + methods) } let defaults = (:) let params = data.matches(regex("(?m)^\s*@\s*(.*?)\s*=\s*(.*)\s*$")) for param in params { let key = param.captures.first() let value = eval(param.captures.last(), scope: (uml: uml)) defaults.insert(key, value) } return uml.diagram(elements, defaults) }