Skip to content

Commit

Permalink
Test command line (#1316)
Browse files Browse the repository at this point in the history
  • Loading branch information
raviqqe authored Jul 8, 2024
1 parent df5eb14 commit 84ca3ea
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 35 deletions.
2 changes: 2 additions & 0 deletions cmd/interpret/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use std::{fs::read, path::PathBuf};
struct Arguments {
#[arg(required(true))]
file: PathBuf,
#[arg()]
arguments: Vec<String>,
#[arg(short = 's', long, default_value_t = DEFAULT_HEAP_SIZE)]
heap_size: usize,
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/minimal/interpret/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {

#[cfg_attr(not(test), no_mangle)]
unsafe extern "C" fn main(argc: isize, argv: *const *const i8) -> isize {
let [_, file] = slice::from_raw_parts(argv, argc as _) else {
let Some(&file) = &slice::from_raw_parts(argv, argc as _).get(1) else {
return 1;
};

Expand All @@ -46,7 +46,7 @@ unsafe extern "C" fn main(argc: isize, argv: *const *const i8) -> isize {
)
.unwrap();

let mmap = Mmap::new(CStr::from_ptr(*file));
let mmap = Mmap::new(CStr::from_ptr(file));

vm.initialize(mmap.as_slice().iter().copied()).unwrap();
vm.run().unwrap();
Expand Down
17 changes: 13 additions & 4 deletions cmd/run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ use std::{
fs::File,
io,
io::{empty, Read},
path::PathBuf,
};

const PRELUDE_SOURCE: &str = include_minified!("prelude.scm");
const COMPILER_PROGRAM: &[u8] = include_r7rs!("compile.scm");
const SCHEME_FILE_EXTENSION: &str = ".scm";

#[derive(Clone, Copy, clap::ValueEnum)]
enum Library {
Expand All @@ -37,7 +37,7 @@ enum Library {
#[command(about, version)]
struct Arguments {
#[arg(required(true))]
files: Vec<PathBuf>,
arguments: Vec<String>,
#[arg(short = 's', long, default_value_t = DEFAULT_HEAP_SIZE)]
heap_size: usize,
#[arg(short, long, default_value = "r7rs")]
Expand All @@ -54,8 +54,17 @@ fn main() -> Result<(), MainError> {
Library::R7rs => PRELUDE_SOURCE.into(),
};
let mut target = vec![];
let index = arguments
.arguments
.iter()
.take_while(|argument| argument.ends_with(SCHEME_FILE_EXTENSION))
.count();

if index == 0 {
return Err("No scheme file specified".into());
}

read_source(&arguments.files, &mut source)?;
read_source(&arguments.arguments[..index], &mut source)?;
compile(&source, &mut target, &mut heap)?;

let mut vm = Vm::new(
Expand All @@ -72,7 +81,7 @@ fn main() -> Result<(), MainError> {
Ok(vm.run()?)
}

fn read_source(files: &[PathBuf], source: &mut String) -> Result<(), io::Error> {
fn read_source(files: &[String], source: &mut String) -> Result<(), io::Error> {
for file in files {
File::open(file)?.read_to_string(source)?;
}
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"repr",
"ribbit",
"rlib",
"rposition",
"rustc",
"rustfmt",
"rustup",
Expand Down
21 changes: 21 additions & 0 deletions features/process-context/command-line.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Feature: Command line
Scenario: Get an argument
Given a file named "main.scm" with:
"""scheme
(import (scheme base) (scheme process-context))
(map write-string (command-line))
"""
When I successfully run `scheme main.scm hello`
Then the stdout should contain "hello"

Scenario: Get two arguments
Given a file named "main.scm" with:
"""scheme
(import (scheme base) (scheme process-context))
(map write-string (command-line))
"""
When I successfully run `scheme main.scm hello world`
Then the stdout should contain "hello"
And the stdout should contain "world"
30 changes: 30 additions & 0 deletions features/process-context/environment-variable.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Feature: Environment variables
Scenario: Get an environment variable
Given a file named "main.scm" with:
"""scheme
(import (scheme base) (scheme process-context))
(write-string (get-environment-variable "FOO"))
"""
And I set the environment variable "FOO" to "bar"
When I successfully run `scheme main.scm`
Then the stdout should contain exactly "bar"

Scenario: Get environment variables
Given a file named "main.scm" with:
"""scheme
(import (scheme base) (scheme process-context))
(for-each
(lambda (pair)
(write-string (car pair))
(write-char #\=)
(write-string (cdr pair))
(newline))
(get-environment-variables))
"""
And I set the environment variable "FOO" to "bar"
And I set the environment variable "BAZ" to "qux"
When I successfully run `scheme main.scm`
Then the stdout should contain "FOO=bar"
And the stdout should contain "BAZ=qux"
23 changes: 20 additions & 3 deletions prelude.scm
Original file line number Diff line number Diff line change
Expand Up @@ -2243,7 +2243,12 @@
(lambda () x)))))

(define-library (scheme process-context)
(export exit emergency-exit)
(export
command-line
emergency-exit
exit
get-environment-variable
get-environment-variables)

(import (scheme base) (scheme lazy) (stak base))

Expand All @@ -2252,10 +2257,22 @@
(define $$get-environment-variables (primitive 29))

(define command-line (delay (map code-points->string ($$command-line))))
(define get-environment-variables (delay ($$get-environment-variables)))
(define get-environment-variables
(delay
(map
(lambda (pair)
(cons
(code-points->string (car pair))
(code-points->string (cdr pair))))
($$get-environment-variables))))

(define (get-environment-variable name)
(assoc name (get-environment-variables)))
(cond
((assoc name (get-environment-variables)) =>
cdr)

(else
#f)))

(define exit-success (data-rib procedure-type '() (cons 0 '())))

Expand Down
47 changes: 25 additions & 22 deletions primitive/src/small.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use heapless::Vec;
use stak_device::Device;
use stak_file::FileSystem;
use stak_process_context::ProcessContext;
use stak_vm::{Memory, Number, PrimitiveSet, Tag, Type, Value};
use stak_vm::{Cons, Memory, Number, PrimitiveSet, Tag, Type, Value};

const PATH_SIZE: usize = 64;

Expand Down Expand Up @@ -173,6 +173,16 @@ impl<D: Device, F: FileSystem, P: ProcessContext> SmallPrimitiveSet<D, F, P> {

Some(path)
}

fn build_string(memory: &mut Memory, string: &str) -> Result<Cons, Error> {
let mut list = memory.null();

for character in string.chars().rev() {
list = memory.cons(Number::new(character as _).into(), list)?;
}

Ok(list)
}
}

impl<D: Device, F: FileSystem, P: ProcessContext> PrimitiveSet for SmallPrimitiveSet<D, F, P> {
Expand Down Expand Up @@ -287,39 +297,32 @@ impl<D: Device, F: FileSystem, P: ProcessContext> PrimitiveSet for SmallPrimitiv
.map(|value| memory.boolean(value).into())
})?,
Primitive::COMMAND_LINE => {
let mut list = memory.null();
memory.set_register(memory.null());

for argument in self.process_context.command_line_rev() {
let mut string = memory.null();

for character in argument.chars().rev() {
string = memory.cons(Number::new(character as _).into(), string)?;
}

list = memory.cons(string.into(), list)?;
let string = Self::build_string(memory, argument)?;
let list = memory.cons(string.into(), memory.register())?;
memory.set_register(list);
}

memory.push(list.into())?;
memory.push(memory.register().into())?;
}
Primitive::ENVIRONMENT_VARIABLES => {
let mut list = memory.null();
memory.set_register(memory.null());

for (key, value) in self.process_context.environment_variables() {
let mut pair = (memory.null(), memory.null());

for character in key.chars().rev() {
pair.0 = memory.cons(Number::new(character as _).into(), pair.0)?;
}
let pair = memory.allocate(memory.null().into(), memory.null().into())?;
let list = memory.cons(pair.into(), memory.register())?;
memory.set_register(list);

for character in value.chars().rev() {
pair.1 = memory.cons(Number::new(character as _).into(), pair.1)?;
}
let string = Self::build_string(memory, key)?;
memory.set_car_value(memory.car(memory.register()), string.into());

let pair = memory.cons(pair.0.into(), pair.1.into())?;
list = memory.cons(pair.into(), list)?;
let string = Self::build_string(memory, value)?;
memory.set_cdr_value(memory.car(memory.register()), string.into());
}

memory.push(list.into())?;
memory.push(memory.register().into())?;
}
_ => return Err(Error::Illegal),
}
Expand Down
9 changes: 7 additions & 2 deletions tools/scheme/mstak-tools/scheme
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
set -e

directory=$(dirname $0)/../../..
raw_arguments="$@"

arguments() {
echo $raw_arguments | tr ' ' '\n' | grep "$@" '\.scm$'
}

export PATH=$directory/target/release_test:$directory/cmd/minimal/target/release:$PATH

cat $directory/prelude.scm "$@" | stak-compile >main.bc
mstak-interpret main.bc
cat $directory/prelude.scm $(arguments) | stak-compile >main.bc
mstak-interpret main.bc $(arguments -v)
9 changes: 7 additions & 2 deletions tools/scheme/stak-tools/scheme
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
set -e

directory=$(dirname $0)/../../..
raw_arguments="$@"

compile() {
if [ -n "$STAK_HOST_INTERPRETER" ]; then
Expand All @@ -12,8 +13,12 @@ compile() {
fi
}

arguments() {
echo $raw_arguments | tr ' ' '\n' | grep "$@" '\.scm$'
}

export PATH=$directory/target/release_test:$PATH

cat $directory/prelude.scm "$@" | compile >main.bc
cat $directory/prelude.scm $(arguments) | compile >main.bc
stak-decode <main.bc >/dev/null
stak-interpret main.bc
stak-interpret main.bc $(arguments -v)

0 comments on commit 84ca3ea

Please sign in to comment.