From b044db3a0262ad52b20159d8033f7e3f204e71b8 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 23 Apr 2024 16:13:28 -0700 Subject: [PATCH 1/4] Allow overridable methods in CompilerOpts --- src/compiler/comptypes.rs | 193 ++++++++++++++++++++++++++++++++++- src/tests/classic/stage_2.rs | 107 ++++--------------- src/tests/compiler/fuzz.rs | 111 +++----------------- 3 files changed, 223 insertions(+), 188 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 5d5cf41e1..90b6444c4 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -324,7 +324,7 @@ pub struct IncludeDesc { } impl IncludeDesc { - pub fn to_sexp(&self) -> Rc { + pub fn override_to_sexp(&self) -> Rc { Rc::new(SExp::Cons( self.kw.clone(), Rc::new(SExp::Atom(self.kw.clone(), b"include".to_vec())), @@ -464,6 +464,197 @@ pub trait CompilerOpts { ) -> Result; } +/// A trait that simplifies implementing one's one CompilerOpts personality. +/// This specifies to a CompilerOptsDelegator that this object contains a +/// CompilerOpts that it uses for most of what it does, allowing end users +/// to opt into a default implementation of all the methods via +/// CompilerOptsDelegator and override only what's desired. +pub trait HasCompilerOptsDelegation { + /// Get this object's inner CompilerOpts. + fn compiler_opts(&self) -> Rc; + /// Call a function that updates this object's CompilerOpts and use the + /// update our own object with the result. Return the new wrapper. + fn update_compiler_opts) -> Rc>(&self, f: F) -> Rc; + + // Defaults. + fn override_filename(&self) -> String { + self.compiler_opts().filename() + } + fn override_code_generator(&self) -> Option { + self.compiler_opts().code_generator() + } + fn override_dialect(&self) -> AcceptedDialect { + self.compiler_opts().dialect() + } + fn override_disassembly_ver(&self) -> Option { + self.compiler_opts().disassembly_ver() + } + fn override_in_defun(&self) -> bool { + self.compiler_opts().in_defun() + } + fn override_stdenv(&self) -> bool { + self.compiler_opts().stdenv() + } + fn override_optimize(&self) -> bool { + self.compiler_opts().optimize() + } + fn override_frontend_opt(&self) -> bool { + self.compiler_opts().frontend_opt() + } + fn override_frontend_check_live(&self) -> bool { + self.compiler_opts().frontend_check_live() + } + fn override_start_env(&self) -> Option> { + self.compiler_opts().start_env() + } + fn override_prim_map(&self) -> Rc, Rc>> { + self.compiler_opts().prim_map() + } + fn override_get_search_paths(&self) -> Vec { + self.compiler_opts().get_search_paths() + } + + fn override_set_dialect(&self, dialect: AcceptedDialect) -> Rc { + self.update_compiler_opts(|o| o.set_dialect(dialect)) + } + fn override_set_search_paths(&self, dirs: &[String]) -> Rc { + self.update_compiler_opts(|o| o.set_search_paths(dirs)) + } + fn override_set_disassembly_ver(&self, ver: Option) -> Rc { + self.update_compiler_opts(|o| o.set_disassembly_ver(ver)) + } + fn override_set_in_defun(&self, new_in_defun: bool) -> Rc { + self.update_compiler_opts(|o| o.set_in_defun(new_in_defun)) + } + fn override_set_stdenv(&self, new_stdenv: bool) -> Rc { + self.update_compiler_opts(|o| o.set_stdenv(new_stdenv)) + } + fn override_set_optimize(&self, opt: bool) -> Rc { + self.update_compiler_opts(|o| o.set_optimize(opt)) + } + fn override_set_frontend_opt(&self, opt: bool) -> Rc { + self.update_compiler_opts(|o| o.set_frontend_opt(opt)) + } + fn override_set_frontend_check_live(&self, check: bool) -> Rc { + self.update_compiler_opts(|o| o.set_frontend_check_live(check)) + } + fn override_set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc { + self.update_compiler_opts(|o| o.set_code_generator(new_compiler)) + } + fn override_set_start_env(&self, start_env: Option>) -> Rc { + self.update_compiler_opts(|o| o.set_start_env(start_env)) + } + fn override_set_prim_map(&self, new_map: Rc, Rc>>) -> Rc { + self.update_compiler_opts(|o| o.set_prim_map(new_map)) + } + fn override_read_new_file( + &self, + inc_from: String, + filename: String, + ) -> Result<(String, Vec), CompileErr> { + self.compiler_opts().read_new_file(inc_from, filename) + } + fn override_compile_program( + &self, + allocator: &mut Allocator, + runner: Rc, + sexp: Rc, + symbol_table: &mut HashMap, + ) -> Result { + self.compiler_opts().compile_program(allocator, runner, sexp, symbol_table) + } +} + +impl CompilerOpts for T { + // Defaults. + fn filename(&self) -> String { + self.override_filename() + } + fn code_generator(&self) -> Option { + self.override_code_generator() + } + fn dialect(&self) -> AcceptedDialect { + self.override_dialect() + } + fn disassembly_ver(&self) -> Option { + self.override_disassembly_ver() + } + fn in_defun(&self) -> bool { + self.override_in_defun() + } + fn stdenv(&self) -> bool { + self.override_stdenv() + } + fn optimize(&self) -> bool { + self.override_optimize() + } + fn frontend_opt(&self) -> bool { + self.override_frontend_opt() + } + fn frontend_check_live(&self) -> bool { + self.override_frontend_check_live() + } + fn start_env(&self) -> Option> { + self.override_start_env() + } + fn prim_map(&self) -> Rc, Rc>> { + self.override_prim_map() + } + fn get_search_paths(&self) -> Vec { + self.override_get_search_paths() + } + + fn set_dialect(&self, dialect: AcceptedDialect) -> Rc { + self.override_set_dialect(dialect) + } + fn set_search_paths(&self, dirs: &[String]) -> Rc { + self.override_set_search_paths(dirs) + } + fn set_disassembly_ver(&self, ver: Option) -> Rc { + self.override_set_disassembly_ver(ver) + } + fn set_in_defun(&self, new_in_defun: bool) -> Rc { + self.override_set_in_defun(new_in_defun) + } + fn set_stdenv(&self, new_stdenv: bool) -> Rc { + self.override_set_stdenv(new_stdenv) + } + fn set_optimize(&self, opt: bool) -> Rc { + self.override_set_optimize(opt) + } + fn set_frontend_opt(&self, opt: bool) -> Rc { + self.override_set_frontend_opt(opt) + } + fn set_frontend_check_live(&self, check: bool) -> Rc { + self.override_set_frontend_check_live(check) + } + fn set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc { + self.override_set_code_generator(new_compiler) + } + fn set_start_env(&self, start_env: Option>) -> Rc { + self.override_set_start_env(start_env) + } + fn set_prim_map(&self, new_map: Rc, Rc>>) -> Rc { + self.override_set_prim_map(new_map) + } + fn read_new_file( + &self, + inc_from: String, + filename: String, + ) -> Result<(String, Vec), CompileErr> { + self.override_read_new_file(inc_from, filename) + } + fn compile_program( + &self, + allocator: &mut Allocator, + runner: Rc, + sexp: Rc, + symbol_table: &mut HashMap, + ) -> Result { + self.override_compile_program(allocator, runner, sexp, symbol_table) + } +} + /// Frontend uses this to accumulate frontend forms, used internally. #[derive(Debug)] pub struct ModAccum { diff --git a/src/tests/classic/stage_2.rs b/src/tests/classic/stage_2.rs index 9ac9aecf6..d72e98da6 100644 --- a/src/tests/classic/stage_2.rs +++ b/src/tests/classic/stage_2.rs @@ -9,7 +9,6 @@ use crate::classic::clvm_tools::binutils::{assemble, assemble_from_ir, disassemb use crate::classic::clvm_tools::clvmc::compile_clvm_text; use crate::classic::clvm_tools::cmds::call_tool; use crate::classic::clvm_tools::ir::reader::read_ir; -use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::classic::clvm_tools::stages::stage_2::compile::{ do_com_prog, get_compile_filename, get_last_path_component, try_expand_macro_for_atom, }; @@ -17,9 +16,9 @@ use crate::classic::clvm_tools::stages::stage_2::helpers::{brun, evaluate, quote use crate::classic::clvm_tools::stages::stage_2::operators::run_program_for_search_paths; use crate::classic::clvm_tools::stages::stage_2::reader::{process_embed_file, read_file}; -use crate::compiler::comptypes::{CompileErr, CompilerOpts, PrimaryCodegen}; -use crate::compiler::dialect::AcceptedDialect; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::comptypes::{CompileErr, CompilerOpts, HasCompilerOptsDelegation}; +use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::sexp::decode_string; use crate::compiler::srcloc::Srcloc; fn test_expand_macro( @@ -300,90 +299,32 @@ fn test_process_embed_file_as_hex() { assert_eq!(name, b"test-embed-from-hex"); } -#[derive(Clone, Debug)] +#[derive(Clone)] struct TestCompilerOptsPresentsOwnFiles { - filename: String, - files: HashMap, + files: Rc>, + opts: Rc, } impl TestCompilerOptsPresentsOwnFiles { fn new(filename: String, files: HashMap) -> Self { - TestCompilerOptsPresentsOwnFiles { filename, files } + TestCompilerOptsPresentsOwnFiles { files: Rc::new(files), opts: Rc::new(DefaultCompilerOpts::new(&filename)) } } } -impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { - fn filename(&self) -> String { - self.filename.clone() +impl HasCompilerOptsDelegation for TestCompilerOptsPresentsOwnFiles { + fn compiler_opts(&self) -> Rc { + self.opts.clone() } - fn code_generator(&self) -> Option { - None + fn update_compiler_opts) -> Rc>(&self, f: F) -> Rc { + let new_opts = f(self.opts.clone()); + Rc::new(TestCompilerOptsPresentsOwnFiles { + opts: new_opts, + .. self.clone() + }) } - fn dialect(&self) -> AcceptedDialect { - AcceptedDialect::default() - } - fn in_defun(&self) -> bool { - false - } - fn stdenv(&self) -> bool { - false - } - fn optimize(&self) -> bool { - false - } - fn frontend_opt(&self) -> bool { - false - } - fn frontend_check_live(&self) -> bool { - false - } - fn start_env(&self) -> Option> { - None - } - fn disassembly_ver(&self) -> Option { - None - } - fn prim_map(&self) -> Rc, Rc>> { - Rc::new(HashMap::new()) - } - fn get_search_paths(&self) -> Vec { - vec![".".to_string()] - } - fn set_dialect(&self, _dialect: AcceptedDialect) -> Rc { - Rc::new(self.clone()) - } - fn set_search_paths(&self, _dirs: &[String]) -> Rc { - Rc::new(self.clone()) - } - fn set_in_defun(&self, _new_in_defun: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_stdenv(&self, _new_stdenv: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_optimize(&self, _opt: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_frontend_opt(&self, _opt: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_frontend_check_live(&self, _check: bool) -> Rc { - Rc::new(self.clone()) - } - fn set_code_generator(&self, _new_compiler: PrimaryCodegen) -> Rc { - Rc::new(self.clone()) - } - fn set_start_env(&self, _start_env: Option>) -> Rc { - Rc::new(self.clone()) - } - fn set_prim_map(&self, _prims: Rc, Rc>>) -> Rc { - Rc::new(self.clone()) - } - fn set_disassembly_ver(&self, _ver: Option) -> Rc { - Rc::new(self.clone()) - } - fn read_new_file( + + fn override_read_new_file( &self, inc_from: String, filename: String, @@ -397,18 +338,6 @@ impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { format!("could not read {filename}"), )) } - fn compile_program( - &self, - _allocator: &mut Allocator, - _runner: Rc, - _sexp: Rc, - _symbol_table: &mut HashMap, - ) -> Result { - Err(CompileErr( - Srcloc::start(&self.filename), - "test object only".to_string(), - )) - } } // Shows that we can inject a compiler opts and have it provide file data. diff --git a/src/tests/compiler/fuzz.rs b/src/tests/compiler/fuzz.rs index 51a5e5378..e9fbd46fe 100644 --- a/src/tests/compiler/fuzz.rs +++ b/src/tests/compiler/fuzz.rs @@ -5,7 +5,6 @@ use rand::prelude::Distribution; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use std::borrow::Borrow; -use std::cell::RefCell; use std::collections::{BTreeSet, HashMap}; use std::fmt::Debug; use std::rc::Rc; @@ -15,8 +14,8 @@ use clvmr::Allocator; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use crate::compiler::clvm::{convert_to_clvm_rs, run}; use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, PrimaryCodegen}; -use crate::compiler::dialect::{detect_modern, AcceptedDialect}; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HasCompilerOptsDelegation}; +use crate::compiler::dialect::detect_modern; use crate::compiler::fuzz::{ExprModifier, FuzzChoice, FuzzGenerator, FuzzTypeParams, Rule}; use crate::compiler::prims::primquote; use crate::compiler::sexp::{enlist, extract_atom_replacement, parse_sexp, SExp}; @@ -41,115 +40,31 @@ pub fn compose_sexp(loc: Srcloc, s: &str) -> Rc { #[derive(Clone)] pub struct TestModuleCompilerOpts { opts: Rc, - written_files: Rc>>>, + // Future use. + // written_files: Rc>>>, } impl TestModuleCompilerOpts { pub fn new(opts: Rc) -> Self { TestModuleCompilerOpts { opts: opts, - written_files: Rc::new(RefCell::new(HashMap::new())), + // Future use. + // written_files: Rc::new(RefCell::new(HashMap::new())), } } +} - fn new_opts(&self, opts: Rc) -> Rc { +impl HasCompilerOptsDelegation for TestModuleCompilerOpts { + fn compiler_opts(&self) -> Rc { self.opts.clone() } + fn update_compiler_opts) -> Rc>(&self, f: F) -> Rc { + let new_opts = f(self.opts.clone()); Rc::new(TestModuleCompilerOpts { - opts, - written_files: self.written_files.clone(), + opts: new_opts, + .. self.clone() }) } } -impl CompilerOpts for TestModuleCompilerOpts { - fn filename(&self) -> String { - self.opts.filename() - } - - fn code_generator(&self) -> Option { - self.opts.code_generator() - } - fn dialect(&self) -> AcceptedDialect { - self.opts.dialect() - } - fn in_defun(&self) -> bool { - self.opts.in_defun() - } - fn stdenv(&self) -> bool { - self.opts.stdenv() - } - fn optimize(&self) -> bool { - self.opts.optimize() - } - fn frontend_opt(&self) -> bool { - self.opts.frontend_opt() - } - fn frontend_check_live(&self) -> bool { - self.opts.frontend_check_live() - } - fn start_env(&self) -> Option> { - self.opts.start_env() - } - fn disassembly_ver(&self) -> Option { - self.opts.disassembly_ver() - } - fn prim_map(&self) -> Rc, Rc>> { - self.opts.prim_map() - } - fn get_search_paths(&self) -> Vec { - self.opts.get_search_paths() - } - fn set_dialect(&self, dialect: AcceptedDialect) -> Rc { - self.new_opts(self.opts.set_dialect(dialect)) - } - fn set_search_paths(&self, dirs: &[String]) -> Rc { - self.new_opts(self.opts.set_search_paths(dirs)) - } - fn set_in_defun(&self, new_in_defun: bool) -> Rc { - self.new_opts(self.opts.set_in_defun(new_in_defun)) - } - fn set_stdenv(&self, new_stdenv: bool) -> Rc { - self.new_opts(self.opts.set_stdenv(new_stdenv)) - } - fn set_optimize(&self, opt: bool) -> Rc { - self.new_opts(self.opts.set_optimize(opt)) - } - fn set_frontend_opt(&self, opt: bool) -> Rc { - self.new_opts(self.opts.set_frontend_opt(opt)) - } - fn set_frontend_check_live(&self, check: bool) -> Rc { - self.new_opts(self.opts.set_frontend_check_live(check)) - } - fn set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc { - self.new_opts(self.opts.set_code_generator(new_compiler)) - } - fn set_start_env(&self, start_env: Option>) -> Rc { - self.new_opts(self.opts.set_start_env(start_env)) - } - fn set_prim_map(&self, prims: Rc, Rc>>) -> Rc { - self.new_opts(self.opts.set_prim_map(prims)) - } - fn set_disassembly_ver(&self, ver: Option) -> Rc { - self.new_opts(self.opts.set_disassembly_ver(ver)) - } - fn read_new_file( - &self, - inc_from: String, - filename: String, - ) -> Result<(String, Vec), CompileErr> { - self.opts.read_new_file(inc_from, filename) - } - fn compile_program( - &self, - allocator: &mut Allocator, - runner: Rc, - sexp: Rc, - symbol_table: &mut HashMap, - ) -> Result { - self.opts - .compile_program(allocator, runner, sexp, symbol_table) - } -} - pub struct PerformCompileResult { pub compiled: Rc, pub source_opts: TestModuleCompilerOpts, From 1f0010062181fbb98e03525a5a81b0a606853a40 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 23 Apr 2024 16:45:33 -0700 Subject: [PATCH 2/4] Fmt --- src/compiler/comptypes.rs | 13 ++++++++++--- src/tests/classic/stage_2.rs | 14 ++++++++++---- src/tests/compiler/fuzz.rs | 11 ++++++++--- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 90b6444c4..1a0263660 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -474,7 +474,10 @@ pub trait HasCompilerOptsDelegation { fn compiler_opts(&self) -> Rc; /// Call a function that updates this object's CompilerOpts and use the /// update our own object with the result. Return the new wrapper. - fn update_compiler_opts) -> Rc>(&self, f: F) -> Rc; + fn update_compiler_opts) -> Rc>( + &self, + f: F, + ) -> Rc; // Defaults. fn override_filename(&self) -> String { @@ -544,7 +547,10 @@ pub trait HasCompilerOptsDelegation { fn override_set_start_env(&self, start_env: Option>) -> Rc { self.update_compiler_opts(|o| o.set_start_env(start_env)) } - fn override_set_prim_map(&self, new_map: Rc, Rc>>) -> Rc { + fn override_set_prim_map( + &self, + new_map: Rc, Rc>>, + ) -> Rc { self.update_compiler_opts(|o| o.set_prim_map(new_map)) } fn override_read_new_file( @@ -561,7 +567,8 @@ pub trait HasCompilerOptsDelegation { sexp: Rc, symbol_table: &mut HashMap, ) -> Result { - self.compiler_opts().compile_program(allocator, runner, sexp, symbol_table) + self.compiler_opts() + .compile_program(allocator, runner, sexp, symbol_table) } } diff --git a/src/tests/classic/stage_2.rs b/src/tests/classic/stage_2.rs index d72e98da6..3f2698469 100644 --- a/src/tests/classic/stage_2.rs +++ b/src/tests/classic/stage_2.rs @@ -16,8 +16,8 @@ use crate::classic::clvm_tools::stages::stage_2::helpers::{brun, evaluate, quote use crate::classic::clvm_tools::stages::stage_2::operators::run_program_for_search_paths; use crate::classic::clvm_tools::stages::stage_2::reader::{process_embed_file, read_file}; -use crate::compiler::comptypes::{CompileErr, CompilerOpts, HasCompilerOptsDelegation}; use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::comptypes::{CompileErr, CompilerOpts, HasCompilerOptsDelegation}; use crate::compiler::sexp::decode_string; use crate::compiler::srcloc::Srcloc; @@ -307,7 +307,10 @@ struct TestCompilerOptsPresentsOwnFiles { impl TestCompilerOptsPresentsOwnFiles { fn new(filename: String, files: HashMap) -> Self { - TestCompilerOptsPresentsOwnFiles { files: Rc::new(files), opts: Rc::new(DefaultCompilerOpts::new(&filename)) } + TestCompilerOptsPresentsOwnFiles { + files: Rc::new(files), + opts: Rc::new(DefaultCompilerOpts::new(&filename)), + } } } @@ -316,11 +319,14 @@ impl HasCompilerOptsDelegation for TestCompilerOptsPresentsOwnFiles { self.opts.clone() } - fn update_compiler_opts) -> Rc>(&self, f: F) -> Rc { + fn update_compiler_opts) -> Rc>( + &self, + f: F, + ) -> Rc { let new_opts = f(self.opts.clone()); Rc::new(TestCompilerOptsPresentsOwnFiles { opts: new_opts, - .. self.clone() + ..self.clone() }) } diff --git a/src/tests/compiler/fuzz.rs b/src/tests/compiler/fuzz.rs index e9fbd46fe..6016d4871 100644 --- a/src/tests/compiler/fuzz.rs +++ b/src/tests/compiler/fuzz.rs @@ -55,12 +55,17 @@ impl TestModuleCompilerOpts { } impl HasCompilerOptsDelegation for TestModuleCompilerOpts { - fn compiler_opts(&self) -> Rc { self.opts.clone() } - fn update_compiler_opts) -> Rc>(&self, f: F) -> Rc { + fn compiler_opts(&self) -> Rc { + self.opts.clone() + } + fn update_compiler_opts) -> Rc>( + &self, + f: F, + ) -> Rc { let new_opts = f(self.opts.clone()); Rc::new(TestModuleCompilerOpts { opts: new_opts, - .. self.clone() + ..self.clone() }) } } From ae4511e29c3f1bb95c9247403e67d29e5b6837d4 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 23 Apr 2024 18:14:09 -0700 Subject: [PATCH 3/4] Turn back --- src/compiler/comptypes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 1a0263660..2df086bf6 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -324,7 +324,7 @@ pub struct IncludeDesc { } impl IncludeDesc { - pub fn override_to_sexp(&self) -> Rc { + pub fn to_sexp(&self) -> Rc { Rc::new(SExp::Cons( self.kw.clone(), Rc::new(SExp::Atom(self.kw.clone(), b"include".to_vec())), From 89fc129bebb645656faa8ced6c0688009bd825a2 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 24 Apr 2024 10:06:47 -0700 Subject: [PATCH 4/4] Fix comment --- src/compiler/comptypes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 2df086bf6..1f446a05f 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -464,7 +464,7 @@ pub trait CompilerOpts { ) -> Result; } -/// A trait that simplifies implementing one's one CompilerOpts personality. +/// A trait that simplifies implementing one's own CompilerOpts personality. /// This specifies to a CompilerOptsDelegator that this object contains a /// CompilerOpts that it uses for most of what it does, allowing end users /// to opt into a default implementation of all the methods via