Browse Source

Add print & REPL functionality to CLI (#267)

* Add basic REPL functionality
* Add utility function to Realm
* Rework flow to allow files to be loaded as well as open a shell
* Remove shell option (not needed now its the default)
* Update README.md & docs/debugging.md
pull/262/head
John Doneth 4 years ago committed by GitHub
parent
commit
d92da39299
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      README.md
  2. 14
      boa/src/realm.rs
  3. 29
      boa_cli/src/main.rs
  4. 7
      docs/debugging.md

14
README.md

@ -74,6 +74,20 @@ see [CHANGELOG](./CHANGELOG.md)
- Run with `cargo run -- test.js` where `test.js` is an existing JS file
- If any JS doesn't work then it's a bug. Please raise an issue!
## Command-line Options
```
USAGE:
boa_cli [FILE]...
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<FILE>... The JavaScript file(s) to be evaluated
```
## Communication
Feel free to contact us on Discord https://discord.gg/tUFFk9Y

14
boa/src/realm.rs

@ -5,8 +5,10 @@
//!A realm is represented in this implementation as a Realm struct with the fields specified from the spec
use crate::{
builtins::{
array, boolean, console, function, json, math, number, object, regexp, string, symbol,
value::{Value, ValueData},
array, boolean, console, function,
function::NativeFunctionData,
json, math, number, object, regexp, string, symbol,
value::{ToValue, Value, ValueData},
},
environment::{
declarative_environment_record::DeclarativeEnvironmentRecord,
@ -65,6 +67,14 @@ impl Realm {
global.set_field_slice("Symbol", symbol::create_constructor(global));
global.set_field_slice("console", console::create_constructor(global));
}
/// Utility to add a function to the global object
pub fn register_global_func(self, func_name: &str, func: NativeFunctionData) -> Self {
self.global_obj
.set_field(func_name.to_value(), func.to_value());
self
}
}
// Similar to new_global_environment in lexical_environment, except we need to return a GlobalEnvirionment

29
boa_cli/src/main.rs

@ -2,29 +2,27 @@
#![warn(clippy::perf)]
#![allow(clippy::cognitive_complexity)]
use boa::builtins::console::log;
use boa::{exec::Executor, forward_val, realm::Realm};
use std::io;
use std::{fs::read_to_string, path::PathBuf};
use structopt::StructOpt;
/// CLI configuration for Boa.
#[derive(Debug, StructOpt)]
#[structopt(author, about)]
struct Opt {
/// The javascript file to be evaluated.
#[structopt(name = "FILE", parse(from_os_str), default_value = "tests/js/test.js")]
/// The JavaScript file(s) to be evaluated.
#[structopt(name = "FILE", parse(from_os_str))]
files: Vec<PathBuf>,
/// Open a boa shell (WIP).
#[structopt(short, long)]
shell: bool,
}
pub fn main() -> Result<(), std::io::Error> {
let args = Opt::from_args();
let realm = Realm::create();
let realm = Realm::create().register_global_func("print", log);
let mut engine = Executor::new(realm);
for file in args.files {
for file in &args.files {
let buffer = read_to_string(file)?;
match forward_val(&mut engine, &buffer) {
@ -33,5 +31,18 @@ pub fn main() -> Result<(), std::io::Error> {
}
}
if args.files.is_empty() {
loop {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer)?;
match forward_val(&mut engine, buffer.trim_end()) {
Ok(v) => println!("{}", v.to_string()),
Err(v) => eprintln!("{}", v.to_string()),
}
}
}
Ok(())
}

7
docs/debugging.md

@ -1,9 +1,10 @@
# Debugging
There are multiple ways to debug what Boa is doing. Or maybe you just want to know how it works under the hood. Or even test some javaScript.
There are multiple ways to debug what Boa is doing. Or maybe you just want to know how it works under the hood. Or even test some JavaScript.
The first thing i usually do is add some JS [here](../tests/js/test.js).
This file will be read if no arguments are provided. Then boa will begin to parse and execute that JS.
One way to do so is to create a file in the root of the repository. For example `test.js`. Then execute `cargo run -- test.js` to run the file with boa.
You can also run boa interactively by simply calling `cargo run` without any arguments to start a shell to execute JS.
These are added in order of how the code is read:

Loading…
Cancel
Save