Can you help at finishing SModel? Dynamic dispatch mapping issue

I've finished an implementation of a solution for designing semantic models (symbols) in Rust using methods containing dynamic dispatches. The reason why I implemented it is not easy to explain to everyone, but anyway, let's focus in the problem.

I'm testing it now to see if it has bugs, and it already yields a problem at the struct keyword in this example (related to the syn crate):

smodel! {
    type Arena = MeaningArena;

    struct Meaning {
        let x: f64 = 0.0;
        let ref y: String = "".into();

        pub fn Meaning() {
            super();
            println!("{}", this.m());
        }

        pub fn m(&self) -> String {
            "".into()
        }

        pub fn m1(&self) {
            println!("base");
        }
    }

    struct FooMeaning: Meaning {
        pub fn FooMeaning() {
            super();
        }

        pub override fn m(&self) -> String {
            "Foo".into()
        }

        pub override fn m1(&self) {
            if true {
                super.m1();
            }
        }
    }
}

I'm getting this at the second struct keyword:

error: expected `fn`
  --> crates\smodel\src\lib.rs:55:13
   |
55 |             struct FooMeaning: Meaning {
   |             ^^^^^^

But I'm really parsing it right:

...
impl Parse for MeaningTree {
    fn parse(input: ParseStream) -> Result<Self> {
        let arena_type_name = parse_meaning_arena_type_name(input)?.to_token_stream();
        let mut meanings = vec![];
        while !input.is_empty() {
            meanings.push(Rc::new(input.parse::<Meaning>()?));
        }
        Ok(Self {
            arena_type_name,
            meanings,
        })
    }
}

...

let braced_content;
let _ = braced!(braced_content in input);

while !braced_content.is_empty() {
    if input.peek(Token![let]) {
        fields.push(Rc::new(parse_meaning_field(input)?));
    } else {
        match parse_meaning_method(input, &name_str)? {
            MeaningMethodOrConstructor::Constructor(ctor) => {
                constructor = Some(ctor);
            },
            MeaningMethodOrConstructor::Method(m) => {
                methods.push(Rc::new(m));
            },
        }
    }
}

Here's the master source:

syn issues resolved: typo.

But I'm getting a panic. Is there a way to know what the macro prints? Edit: right, it prints...

I'm back.

The only bug right now is that dynamic dispatch logic is not prepended to methods.

Here are some pieces of code:

// If the method is marked as "override"
//
// * Lookup for a method with the same name in one of the base meanings
// * Contribute "overriding" return call code to the respective
//   override logic mapping according to meaning inheritance.
if node.is_override {
    if let Some(base_method) = meaning.lookup_method_in_base_meaning(&slot.name()) {
        self.perform_override(&slot.name(), base_method.override_logic_mapping(), &base_method.defined_in(), meaning, &input_args);
    } else {
        name.span().unwrap().error(format!("Found no method '{}' in base.", slot.name())).emit();
    }
}

Another one:

// Contribute the method #method_name with prepended dynamic dispatch logic,
// invoking `self.#nondispatch_name(#input_args)` at the end of the method body,
// to the `impl` output.
let dynamic_dispatch = self.generate_dynamic_dispatch(slot.override_logic_mapping());

meaning.method_output().borrow_mut().extend(quote! {
    #(#attr)*
    #vis fn #name #(#type_params)*(&self, #inputs) #result_annotation #where_clause {
        #dynamic_dispatch
        self.#nondispatch_name_id(#input_args)
    }
});

generate_dynamic_dispatch()

fn generate_dynamic_dispatch(&self, mapping: SharedMap<Symbol, Rc<OverrideLogicMapping>>) -> proc_macro2::TokenStream {
    let mut out = proc_macro2::TokenStream::new();
    let mut first = true;
    for (submeaning, logic) in mapping.borrow().iter() {
        let submeaning_name = submeaning.name();
        if !first {
            out.extend(quote! { else });
        }
        let mut d1 = self.generate_dynamic_dispatch(logic.override_logic_mapping());
        if d1.is_empty() {
            if let Some(code) = logic.override_code() {
                d1.extend(code);
            }
        } else if let Some(code) = logic.override_code() {
            d1.extend(quote! { else { #code } });
        }
        out.extend(quote! {
            if self.is::<#submeaning_name>() {
                #d1
            }
        });
        first = false;
    }
    out
}

For this override logic mapping I'm using a SharedMap, which is a layer over Rc<RefCell<HashMap<K, V>>>, deriving Clone to clone by reference.

The override logic mapping contains the dynamic dispatch code.

When I println!("{}", logic_mapping.borrow().len()); I get 0 at the dynamic dispatch area; in the override area, I get, correctly, 1, after assigning a key-value to logic_mapping.

The problem is that I was doing just one pass for the "meaning" data type structures, accidentally.

I had to do one second pass that is specific for the dynamic dispatch, after all overriding is processed.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.