fall back on shell command behaviour for undefined variables
Signed-off-by: Ava Hahn <ava@sunnypup.io>
This commit is contained in:
parent
0babc1986a
commit
c05b94e92a
5 changed files with 84 additions and 15 deletions
|
|
@ -22,3 +22,4 @@ phf = { version = "0.11", default-features = false, features = ["macros"] }
|
|||
[features]
|
||||
default = ["posix"]
|
||||
posix = ["dep:nix", "dep:libc"]
|
||||
implicit-load = ["posix"]
|
||||
|
|
|
|||
24
Shell.org
24
Shell.org
|
|
@ -170,3 +170,27 @@ Or:
|
|||
|
||||
(pacman-search "xfce4")
|
||||
#+END_EXAMPLE
|
||||
|
||||
* Implicit Load
|
||||
Typically, any call to an undefined function, lambda, or symbol will result in an undefined symbol error. For example, here is a call to GCC without explicitly prepending the ~load~ function:
|
||||
#+BEGIN_EXAMPLE
|
||||
> (gcc myfile.c -o myfile)
|
||||
|
||||
** ERROR TRACEBACK
|
||||
> gdb: (is an undefined symbol)
|
||||
Please refactor forms and try again...
|
||||
#+END_EXAMPLE
|
||||
|
||||
With the ~implicit load~ feature any call to an undefined function will trigger the ~load~ function as if it had been there the whole time. The above example would yield a new subprocess running GCC (assuming it is installed and accessible). This allows users to quickly type shell commands at the prompt as if they were using a standard shell. Any reference to an undefined symbol outside of where a function would be will still cause an error.
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
> ls -la .config
|
||||
|
||||
...... (redacted directory list) .....
|
||||
#+END_EXAMPLE
|
||||
|
||||
Implicit load can be used by building relish with the following command:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
cargo build -F implicit-load
|
||||
#+END_EXAMPLE
|
||||
|
|
|
|||
|
|
@ -57,4 +57,6 @@ pub mod aux {
|
|||
pub use crate::stl::posix::ShellState;
|
||||
#[cfg(feature="posix")]
|
||||
pub use crate::stl::posix::check_jobs;
|
||||
#[cfg(feature="posix")]
|
||||
pub use crate::stl::posix::POSIX_LOAD_NAME;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
pub const POSIX_LOAD_NAME: &str = "load";
|
||||
|
||||
pub struct ShellState {
|
||||
pub parent_pid: Pid,
|
||||
pub parent_sid: Pid,
|
||||
|
|
@ -273,7 +275,7 @@ const LOAD_DOCSTRING: &str = "Calls a binary off disk with given arguments.
|
|||
Arguments may be of any type except lambda. If a symbol is not defined it will be passed as a string.
|
||||
first argument (command name) will be found on path (or an error returned).
|
||||
|
||||
examples:
|
||||
examples:call
|
||||
(l ping google.com)
|
||||
(let ((ping-count 4))
|
||||
(l ping -c ping-count google.com))
|
||||
|
|
@ -787,7 +789,7 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
|||
syms.insert(
|
||||
String::from("l"),
|
||||
Symbol {
|
||||
name: String::from("load"),
|
||||
name: String::from(POSIX_LOAD_NAME),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: String::from(LOAD_DOCSTRING),
|
||||
|
|
@ -799,9 +801,9 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
|||
);
|
||||
|
||||
syms.insert(
|
||||
String::from("load"),
|
||||
String::from(POSIX_LOAD_NAME),
|
||||
Symbol {
|
||||
name: String::from("load"),
|
||||
name: String::from(POSIX_LOAD_NAME),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: String::from(LOAD_DOCSTRING),
|
||||
|
|
|
|||
46
src/sym.rs
46
src/sym.rs
|
|
@ -18,6 +18,7 @@
|
|||
use crate::eval::eval;
|
||||
use crate::error::{Traceback, start_trace};
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use crate::stl::posix::POSIX_LOAD_NAME;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -129,8 +130,42 @@ impl SymTable {
|
|||
args: &Seg,
|
||||
call_func: bool,
|
||||
) -> Result<Box<Ctr>, Traceback> {
|
||||
let outer_scope_seg: Seg;
|
||||
let mut call_args = args;
|
||||
let mut name_token = name.to_string();
|
||||
let mut symbol = match self.remove(name) {
|
||||
Some(s) => s,
|
||||
|
||||
/* implicit load:
|
||||
* on a call to an undefined function
|
||||
* assume a shell command is being run
|
||||
*/
|
||||
None if cfg!(feature="implicit-load")
|
||||
&& call_func => match self.remove(&POSIX_LOAD_NAME.to_string()) {
|
||||
Some(s) => {
|
||||
name_token = String::from(POSIX_LOAD_NAME);
|
||||
/* highly unfortunate circumstance
|
||||
* we must now rebuild the original ast
|
||||
* costs a whole clone of the args
|
||||
* this feature is non-standard
|
||||
*/
|
||||
outer_scope_seg = Seg::from(
|
||||
Box::from(Ctr::Symbol(name.to_string())),
|
||||
if let Ctr::None = *args.car {
|
||||
Box::from(Ctr::None)
|
||||
} else {
|
||||
Box::from(Ctr::Seg(args.clone()))
|
||||
},
|
||||
);
|
||||
call_args = &outer_scope_seg;
|
||||
s
|
||||
},
|
||||
None => return Err(
|
||||
Traceback::new()
|
||||
.with_trace(("(implicit load)", "(load function not found)").into())
|
||||
)
|
||||
},
|
||||
|
||||
None => return Err(
|
||||
Traceback::new()
|
||||
.with_trace((name, "(is an undefined symbol)").into())
|
||||
|
|
@ -139,7 +174,7 @@ impl SymTable {
|
|||
// will re-increment when inserted
|
||||
// but we dont want to increment it
|
||||
symbol.__generation -= 1;
|
||||
self.insert(name.to_string(), symbol.clone());
|
||||
self.insert(name_token, symbol.clone());
|
||||
if let ValueType::VarForm(ref val) = symbol.value {
|
||||
match **val {
|
||||
Ctr::Lambda(ref l) if call_func => {
|
||||
|
|
@ -165,7 +200,7 @@ impl SymTable {
|
|||
}
|
||||
}
|
||||
if call_func {
|
||||
symbol.call(args, self)
|
||||
symbol.call(call_args, self)
|
||||
} else {
|
||||
// its a function but call_func is off
|
||||
Ok(Box::new(Ctr::Symbol(name.to_string())))
|
||||
|
|
@ -173,7 +208,10 @@ impl SymTable {
|
|||
}
|
||||
|
||||
pub fn is_function_type(&self, name: &String) -> Option<bool> {
|
||||
if let ValueType::VarForm(ref val) = self.get(name)?.value {
|
||||
match self.get(name) {
|
||||
/* implicit-load: assume you just drew load function */
|
||||
None if cfg!(feature="implicit-load") => Some(true),
|
||||
Some(value) => if let ValueType::VarForm(ref val) = value.value {
|
||||
match **val {
|
||||
Ctr::Lambda(_) => Some(true),
|
||||
Ctr::Symbol(ref n) => self.is_function_type(n),
|
||||
|
|
@ -181,6 +219,8 @@ impl SymTable {
|
|||
}
|
||||
} else {
|
||||
Some(true)
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue