Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(nova_vm): Reorganize folder structure #33

Merged
merged 1 commit into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
## Warning: This project is a Work In Progress, and is very far from being suitable for use

Nova is a [JavaScript](https://tc39.es/ecma262) and [WebAssembly](https://webassembly.org) engine written in Rust.
Nova is a [JavaScript](https://tc39.es/ecma262) and
[WebAssembly](https://webassembly.org) engine written in Rust.

The engine is exposed as a library with an API for implementation in Rust projects which themselves must serve as a runtime for JavaScript code.
The engine is exposed as a library with an API for implementation in Rust
projects which themselves must serve as a runtime for JavaScript code.

The core of our team is on our [Discord server](https://discord.gg/RTrgJzXKUM).
2 changes: 1 addition & 1 deletion code.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
var asd = "foobar"
var asd = "foobar";
2 changes: 1 addition & 1 deletion nova_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let allocator = Default::default();
let source_type: SourceType = Default::default();
let parser = Parser::new(&allocator, &file, source_type.with_typescript(false));
let result = parser.parse();
let _result = parser.parse();

// let mut vm = VM {
// source: &file,
Expand Down
21 changes: 21 additions & 0 deletions nova_vm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Project structure

The Nova VM source structure is as follows:

1. The `ecmascript` folder contains all code relating to the ECMAScript
specification.
1. The `engine` folder contains Nova engine specific code such as bytecode.
1. The `heap` folder contains the setup for the heap of the VM and the direct
APIs to work with it.

### ECMAScript folder structure

The ECMAScript folder will have its own READMEs to better describe various
details of the structure but the basic idea is to stay fairly close to the
ECMAScript specification text and its structure.

As an example, the `ecmascript/types` folder corresponds to the specification's
section 6, `ECMAScript Data Types and Values`. That section has two subsections,
6.1 `ECMASCript Language Types` and 6.2 `ECMAScript Specification Types`, which
then correspond to the `ecmascript/types/language` and `ecmascript/types/spec`
folders respectively.
4 changes: 4 additions & 0 deletions nova_vm/src/ecmascript.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod builtins;
pub mod execution;
pub mod scripts_and_modules;
pub mod types;
50 changes: 50 additions & 0 deletions nova_vm/src/ecmascript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## ECMAScript

This folder contains the code for things mentioned directly in the
[ECMAScript language specification](https://tc39.es/ecma262/). As much as is
reasonable, the structure within this folder should be similar to the
specification text and code should reuse terms from the specification directly.

### Crossreferencing

#### 6. ECMAScript Data Types and Values

Found in the [`types`](./types/) folder.

#### 7. Abstract operations

Currently mostly found as methods on `Value`.

Maybe move to [`abstract_operations`](./abstract_operation)?

#### 8. Syntax-Directed Operations

This is more about the parsing so I am not sure if this needs to be in the
engine at all.

If this ends up being needed then it will be in a [`syntax`](./syntax/) folder.

#### 9. Executable Code and Execution Contexts

Found in the [`execution`](./execution/) folder.

#### 10. Ordinary and Exotic Objects Behaviours

Currently mostly found in `builtins` but maybe move to
[`behaviours`](./behaviours)?

On the other hand, this part of the spec also contains the subsection 10.3
Built-in Function Objects and various other built-in related things so it might
be okay to keep this in `builtins` in an inline sort of way.

#### 11-15. ECMAScript Language, and 18. Error Handling and Language Extensions

This is all syntax (and then some) and will not be found in the engine.

#### 16. ECMAScript Language: Scripts and Modules

Found in the [`scripts_and_modules`](./scripts_and_modules/) folder.

#### 18. ECMAScript Standard Built-in Objects, and 19-28.

Should be found in the [`builtins`](./builtins/) folder.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{create_builtin_function, ArgumentsList, Behaviour, Builtin, BuiltinFunctionArgs};
use crate::{
use crate::ecmascript::{
execution::{Agent, JsResult},
types::{Object, Value},
};
Expand All @@ -21,9 +21,9 @@ impl Builtin for ArrayConstructor {

impl ArrayConstructor {
fn behaviour(
agent: &mut Agent,
this_value: Value,
arguments: ArgumentsList,
_agent: &mut Agent,
_this_value: Value,
_arguments: ArgumentsList,
) -> JsResult<Value> {
todo!();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{
execution::{Agent, Intrinsics, JsResult, Realm, RealmIdentifier},
ecmascript::{
execution::{Agent, JsResult, RealmIdentifier},
types::{Function, Object, PropertyDescriptor, Value},
},
heap::CreateHeapData,
types::{Function, Object, PropertyDescriptor, Value},
Heap,
};

#[derive(Debug)]
Expand Down Expand Up @@ -53,20 +54,16 @@ impl<'a, 'ctx: 'a, 'host: 'ctx> BuiltinFunctionArgs<'a, 'ctx, 'host> {
/// https://tc39.es/ecma262/#sec-createbuiltinfunction
pub fn create_builtin_function<'a, 'b: 'a>(
agent: &mut Agent<'b, 'b>,
behaviour: Behaviour,
_behaviour: Behaviour,
args: BuiltinFunctionArgs<'a, 'b, 'b>,
) -> Function {
// 1. If realm is not present, set realm to the current Realm Record.
let realm_id = args.realm.unwrap_or(agent.current_realm_id());

// 2. If prototype is not present, set prototype to realm.[[Intrinsics]].[[%Function.prototype%]].
let prototype = args.prototype.unwrap_or_else(|| {
agent
.get_realm(realm_id)
.intrinsics()
.function_prototype()
.into()
});
let prototype = args
.prototype
.unwrap_or_else(|| agent.get_realm(realm_id).intrinsics().function_prototype());
let heap = &mut agent.heap;

// TODO: Steps 3-4
Expand All @@ -83,7 +80,7 @@ pub fn create_builtin_function<'a, 'b: 'a>(
// 8. Set func.[[Realm]] to realm.
// NOTE: Heap data is implicitly attached to the Realm so I don't think
// this matters.
let object = heap.create_object_with_prototype(prototype);
let _object = heap.create_object_with_prototype(prototype);

// 9. Set func.[[InitialName]] to null.
// TODO: This is non-standard.
Expand All @@ -103,15 +100,15 @@ pub fn create_builtin_function<'a, 'b: 'a>(
Function(func)
}

pub fn define_builtin_function<'a, 'b>(
pub fn define_builtin_function<'b>(
agent: &mut Agent<'b, 'b>,
object: Object,
name: &'a str,
_object: Object,
name: &str,
behaviour: RegularFn,
length: u32,
realm: RealmIdentifier<'b, 'b>,
) -> JsResult<()> {
let function = create_builtin_function(
let _function = create_builtin_function(
agent,
Behaviour::Regular(behaviour),
BuiltinFunctionArgs::new(length, name, realm),
Expand All @@ -121,17 +118,17 @@ pub fn define_builtin_function<'a, 'b>(
}

pub fn define_builtin_property(
object: Object,
name: &'static str,
descriptor: PropertyDescriptor,
_object: Object,
_name: &'static str,
_descriptor: PropertyDescriptor,
) -> JsResult<()> {
Ok(())
}

pub fn todo_builtin(agent: &mut Agent, _: Value, _: ArgumentsList) -> JsResult<Value> {
agent.throw_exception(
crate::execution::agent::ExceptionType::SyntaxError,
crate::ecmascript::execution::agent::ExceptionType::SyntaxError,
"TODO: Builtin not implemented.",
);
Err(())
Err(Default::default())
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use std::{cell::RefCell, rc::Rc};

use oxc_ast::ast::{FormalParameters, FunctionBody};

use crate::{
execution::{
Agent, EnvironmentIndex, JsResult, PrivateEnvironmentIndex, RealmIdentifier, ScriptOrModule,
},
use crate::ecmascript::{
execution::{Agent, EnvironmentIndex, JsResult, PrivateEnvironmentIndex, RealmIdentifier},
scripts_and_modules::ScriptOrModule,
types::{Number, Object, PropertyDescriptor, PropertyKey, Value},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use super::{
create_builtin_function, todo_builtin, ArgumentsList, Behaviour, Builtin, BuiltinFunctionArgs,
};
use crate::{
execution::{Agent, JsResult},
ecmascript::{
execution::{Agent, JsResult},
types::{Number, Object, PropertyDescriptor, Value},
},
heap::CreateHeapData,
types::{Number, Object, PropertyDescriptor, Value},
SmallInteger,
};

Expand Down Expand Up @@ -185,7 +187,7 @@ impl NumberConstructor {
/// https://tc39.es/ecma262/#sec-number-constructor-number-value
fn behaviour(
agent: &mut Agent,
this_value: Value,
_this_value: Value,
arguments: ArgumentsList,
new_target: Option<Object>,
) -> JsResult<Value> {
Expand All @@ -212,7 +214,7 @@ impl NumberConstructor {
};

// 3. If NewTarget is undefined, return n.
let Some(new_target) = new_target else {
let Some(_new_target) = new_target else {
return Ok(n);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{
use crate::ecmascript::{
execution::{Agent, JsResult},
types::{InternalMethods, Object, PropertyDescriptor, PropertyKey, Value},
};
Expand Down Expand Up @@ -46,7 +46,7 @@ fn set_prototype_of(
prototype: Option<Object>,
) -> JsResult<bool> {
// 1. Return OrdinarySetPrototypeOf(O, V).
return ordinary_set_prototype_of(agent, object, prototype);
ordinary_set_prototype_of(agent, object, prototype)
}

/// 10.1.2.1 OrdinarySetPrototypeOf ( O, V )
Expand Down Expand Up @@ -474,7 +474,6 @@ fn validate_and_apply_property_descriptor(
set: descriptor.set.or(current.set),
enumerable: descriptor.enumerable.or(current.enumerable),
configurable: descriptor.configurable.or(current.configurable),
..Default::default()
},
);
}
Expand Down Expand Up @@ -506,7 +505,7 @@ pub fn ordinary_has_property(
let has_own = (object.internal_methods(agent).get_own_property)(agent, object, property_key)?;

// 2. If hasOwn is not undefined, return true.
if let Some(_) = has_own {
if has_own.is_some() {
return Ok(true);
}

Expand Down Expand Up @@ -569,7 +568,7 @@ pub fn ordinary_get(

// 5. Let getter be desc.[[Get]].
// 6. If getter is undefined, return undefined.
let Some(getter) = descriptor.get else {
let Some(_getter) = descriptor.get else {
return Ok(Value::Undefined);
};

Expand Down Expand Up @@ -703,7 +702,7 @@ pub fn ordinary_set_with_own_descriptor(

// 4. Let setter be ownDesc.[[Set]].
// 5. If setter is undefined, return false.
let Some(setter) = own_descriptor.set else {
let Some(_setter) = own_descriptor.set else {
return Ok(false);
};

Expand Down Expand Up @@ -757,9 +756,12 @@ fn own_property_keys(agent: &mut Agent, object: Object) -> JsResult<Vec<Property

/// 10.1.11.1 OrdinaryOwnPropertyKeys ( O )
/// https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
pub fn ordinary_own_property_keys(agent: &mut Agent, object: Object) -> JsResult<Vec<PropertyKey>> {
pub fn ordinary_own_property_keys(
_agent: &mut Agent,
_object: Object,
) -> JsResult<Vec<PropertyKey>> {
// 1. Let keys be a new empty List.
let mut keys = Vec::new();
let keys = Vec::new();

// 2. For each own property key P of O such that P is an array index, in ascending numeric
// index order, do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ pub use environments::{
FunctionEnvironment, FunctionEnvironmentIndex, GlobalEnvironment, GlobalEnvironmentIndex,
ObjectEnvironment, ObjectEnvironmentIndex, PrivateEnvironment, PrivateEnvironmentIndex,
};
pub use execution_context::{ECMAScriptCode, ExecutionContext, ScriptOrModule};
pub use execution_context::{ECMAScriptCode, ExecutionContext};
pub use realm::{Intrinsics, Realm, RealmIdentifier};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{ExecutionContext, Realm, RealmIdentifier};
use crate::{
types::{Object, Symbol, Value},
ecmascript::types::{Object, Symbol, Value},
Heap,
};
use std::collections::HashMap;
Expand All @@ -12,7 +12,10 @@ pub struct Options {
pub print_bytecode: bool,
}

pub type JsResult<T> = std::result::Result<T, ()>;
pub type JsResult<T> = std::result::Result<T, JsError>;

#[derive(Debug, Default, Clone, Copy)]
pub struct JsError {}

// #[derive(Debug)]
// pub struct PreAllocated;
Expand Down Expand Up @@ -60,7 +63,7 @@ impl<'ctx, 'host> Agent<'ctx, 'host> {

/// 5.2.3.2 Throw an Exception
/// https://tc39.es/ecma262/#sec-throw-an-exception
pub fn throw_exception(&mut self, kind: ExceptionType, message: &'static str) -> () {
pub fn throw_exception(&mut self, _kind: ExceptionType, _message: &'static str) -> JsError {
todo!()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{JsResult, Realm};
use crate::types::Function;
use crate::ecmascript::types::Function;

/// 19.2.1.2 HostEnsureCanCompileStrings ( calleeRealm )
/// https://tc39.es/ecma262/#sec-hostensurecancompilestrings
Expand All @@ -11,5 +11,5 @@ pub fn host_ensure_can_compile_strings(_: &mut Realm) -> JsResult<()> {
/// https://tc39.es/ecma262/#sec-hosthassourcetextavailable
pub fn host_has_source_text_available(_: Function) -> bool {
// The default implementation of HostHasSourceTextAvailable is to return true.
return true;
true
}
Loading