From 290bd9171941162bcf3c917bfd400a3241e275f7 Mon Sep 17 00:00:00 2001 From: "Justin (:flaviusb) Marsh" Date: Sun, 5 Mar 2023 12:03:04 +1300 Subject: [PATCH] More work on fnRunnerHandler. Working on the argument parsing. --- do_with_in_base/Cargo.toml | 1 + do_with_in_base/src/lib.rs | 64 +++++++++++++++++++++++++++++++++++--- scratch | 4 +++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/do_with_in_base/Cargo.toml b/do_with_in_base/Cargo.toml index 4f91ab7..da36b72 100644 --- a/do_with_in_base/Cargo.toml +++ b/do_with_in_base/Cargo.toml @@ -17,3 +17,4 @@ doctest = false quote = "1.0" syn = { version = "1.0", features = ["full", "visit", "fold", "extra-traits", "parsing", "proc-macro"] } proc-macro2 = "1.0" +bimap = "0.6.2" diff --git a/do_with_in_base/src/lib.rs b/do_with_in_base/src/lib.rs index 79f3d8e..b74e583 100644 --- a/do_with_in_base/src/lib.rs +++ b/do_with_in_base/src/lib.rs @@ -2,6 +2,7 @@ extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; extern crate proc_macro2; +extern crate bimap; use proc_macro::{TokenStream, TokenTree}; use proc_macro2::TokenTree as TokenTree2; @@ -2103,14 +2104,67 @@ pub fn internalFnRunner(c: Configuration, v: Variable // Create an argument matcher // External name and internal name // Declaration order and invocation order - // Vec> ← defaults via position - // HashMap ← give names to things with names - // HashMap ← give positions to things with names - let required_args: Vec = Vec::new(); // Put the inner name of each argument with no default in here; we check at the end that we have them all. + let mut defaults_by_declaration_position: Vec> = Vec::new(); + let mut thunks_by_invocation_position: Vec> = Vec::new(); + // The inner and outer names index into defaults_by_position, which is our 'root list of args' + let mut inner_names: bimap::BiMap = bimap::BiMap::::new(); + let mut outer_names: bimap::BiMap = bimap::BiMap::::new(); + // Once we have all the declaration site stuff done, we populate the thunks_by_invocation_position + // and then process them. + // Thunks get run in an environment built up of things invoked to the left of them using the external names. + // Defaults get run in an environment built up of things defined to the left of them using the internal names. + // We have a list of internal/external names with assigned values + // The order of processing is... let mut call_site_stream = t.clone().into_iter(); call_site_stream.next(); // The function invocation token if let Some(TokenTree2::Group(grp)) = call_site_stream.next() { - let mut call_site_args = grp.stream(); + let mut call_site_args = grp.stream().into_iter().peekable(); + let mut declaration_site_args = args.clone().stream().into_iter().peekable(); + // First we parse the declaration site args to generate a parser for the use site args + let mut more = true; + while more { + // $pi ≡ Punct("_") or Ident + // $val ≡ Group or Ident or Literal + // $args ≡ ($pi $pi? ("=" $val)?),* + let first = match declaration_site_args.next() { + None => {more = false; continue}, + Some(TokenTree2::Punct(punct)) if punct.as_char() == ',' => continue, + Some(TokenTree2::Punct(punct)) if punct.as_char() == '_' => None, + Some(TokenTree2::Ident(ident)) => Some(ident.to_string()), + Some(it) => { + let msg = format!("Got ⌜{}⌝ in argument list for function \"{}\"; expected '_' or an ident.", it, name); + let sp = it.span(); + return Err((v, quote_spanned!{sp=> compile_error!{ #msg }})); + }, + }; + let (has_second, might_have_third) = match declaration_site_args.peek() { + None => {more = false; (false, false)}, + Some(TokenTree2::Punct(punct)) if punct.as_char() == ',' => (false, false), + Some(TokenTree2::Punct(punct)) if punct.as_char() == '_' => (true, true), + Some(TokenTree2::Ident(ident)) => (true, true), + Some(TokenTree2::Punct(punct)) if punct.as_char() == '=' => (false, true), + Some(it) => { + let msg = format!("Got ⌜{}⌝ in argument list for function \"{}\"; expected '_' or an ident.", it, name); + let sp = it.span(); + return Err((v, quote_spanned!{sp=> compile_error!{ #msg }})); + }, + }; + if has_second { + // We get the value and do everything else inside here too + /*let second = match declaration_site_args.next() { + None => { + }, + Some(...) => { + }, + Some(x) => { + }, + };*/ + } else { + // We stuff the first thing in the + } + if might_have_third { + } + } todo!() } else { let msg = format!("Did not get args in invocation of function {}.", name); diff --git a/scratch b/scratch index 67143d8..0b9d281 100644 --- a/scratch +++ b/scratch @@ -72,6 +72,10 @@ vec of default values get arg values from caller to populate actual values based on args, push all of those to env, then got through defaults pushing in to the environment left-to-right in the declaration +$pi ≡ Punct("_") or Ident +$val ≡ Group or Ident or Literal +($pi $pi? ("=" $val)?),* + ---