runmat_vm/compiler/
classes.rs1use crate::compiler::core::Compiler;
4use crate::compiler::CompileError;
5use crate::instr::Instr;
6
7impl Compiler {
8 fn attr_access_from_str(s: &str) -> runmat_builtins::Access {
9 match s.to_ascii_lowercase().as_str() {
10 "private" => runmat_builtins::Access::Private,
11 _ => runmat_builtins::Access::Public,
12 }
13 }
14
15 pub(crate) fn parse_prop_attrs(
16 attrs: &Vec<runmat_parser::Attr>,
17 ) -> (bool, bool, String, String) {
18 let mut is_static = false;
19 let mut is_dependent = false;
20 let mut get_acc = runmat_builtins::Access::Public;
21 let mut set_acc = runmat_builtins::Access::Public;
22 for a in attrs {
23 if a.name.eq_ignore_ascii_case("Static") {
24 is_static = true;
25 }
26 if a.name.eq_ignore_ascii_case("Dependent") {
27 is_dependent = true;
28 }
29 if a.name.eq_ignore_ascii_case("Access") {
30 if let Some(v) = &a.value {
31 let acc = Self::attr_access_from_str(v.trim_matches('\'').trim());
32 get_acc = acc.clone();
33 set_acc = acc;
34 }
35 }
36 if a.name.eq_ignore_ascii_case("GetAccess") {
37 if let Some(v) = &a.value {
38 get_acc = Self::attr_access_from_str(v.trim_matches('\'').trim());
39 }
40 }
41 if a.name.eq_ignore_ascii_case("SetAccess") {
42 if let Some(v) = &a.value {
43 set_acc = Self::attr_access_from_str(v.trim_matches('\'').trim());
44 }
45 }
46 }
47 let gs = match get_acc {
48 runmat_builtins::Access::Private => "private".to_string(),
49 _ => "public".to_string(),
50 };
51 let ss = match set_acc {
52 runmat_builtins::Access::Private => "private".to_string(),
53 _ => "public".to_string(),
54 };
55 (is_static, is_dependent, gs, ss)
56 }
57
58 pub(crate) fn parse_method_attrs(attrs: &Vec<runmat_parser::Attr>) -> (bool, String) {
59 let mut is_static = false;
60 let mut access = runmat_builtins::Access::Public;
61 for a in attrs {
62 if a.name.eq_ignore_ascii_case("Static") {
63 is_static = true;
64 }
65 if a.name.eq_ignore_ascii_case("Access") {
66 if let Some(v) = &a.value {
67 access = Self::attr_access_from_str(v.trim_matches('\'').trim());
68 }
69 }
70 }
71 let acc_str = match access {
72 runmat_builtins::Access::Private => "private".to_string(),
73 _ => "public".to_string(),
74 };
75 (is_static, acc_str)
76 }
77
78 pub(crate) fn compile_class_def(
79 &mut self,
80 name: &str,
81 super_class: &Option<String>,
82 members: &[runmat_hir::HirClassMember],
83 ) -> Result<(), CompileError> {
84 let mut props: Vec<(String, bool, String, String)> = Vec::new();
85 let mut methods: Vec<(String, String, bool, String)> = Vec::new();
86 for m in members {
87 match m {
88 runmat_hir::HirClassMember::Properties { names, attributes } => {
89 let (is_static, is_dependent, get_access, set_access) =
90 Self::parse_prop_attrs(attributes);
91 for n in names {
92 let enc = if is_dependent {
93 format!("@dep:{n}")
94 } else {
95 n.clone()
96 };
97 props.push((enc, is_static, get_access.clone(), set_access.clone()));
98 }
99 }
100 runmat_hir::HirClassMember::Methods { body, attributes } => {
101 let (is_static, access) = Self::parse_method_attrs(attributes);
102 for s in body {
103 if let runmat_hir::HirStmt::Function { name: mname, .. } = s {
104 methods.push((mname.clone(), mname.clone(), is_static, access.clone()));
105 }
106 }
107 }
108 _ => {}
109 }
110 }
111 self.emit(Instr::RegisterClass {
112 name: name.to_string(),
113 super_class: super_class.clone(),
114 properties: props,
115 methods,
116 });
117 Ok(())
118 }
119}