Skip to content

Commit

Permalink
js: Implement value member access in bytecode vm
Browse files Browse the repository at this point in the history
  • Loading branch information
simonwuelker committed May 18, 2024
1 parent 121ea48 commit abb0d2d
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 11 deletions.
17 changes: 16 additions & 1 deletion crates/js/src/bytecode/builder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{BasicBlock, BasicBlockExit, Instruction, Program};
use crate::{value::object, Value};
use crate::{parser::identifiers::Identifier, value::object, Value};

#[derive(Clone, Copy, Debug)]
pub struct Register(usize);
Expand Down Expand Up @@ -313,6 +313,21 @@ impl<'a> BasicBlockBuilder<'a> {
}
}

pub fn member_access_with_identifier(
&mut self,
base: Register,
identifier: Identifier,
) -> Register {
let dst = self.allocate_register();
let instruction = Instruction::MemberAccessWithIdentifier {
base,
identifier,
dst,
};
self.push_instruction(instruction);
dst
}

pub fn create_data_property_or_throw(
&mut self,
object: Register,
Expand Down
7 changes: 6 additions & 1 deletion crates/js/src/bytecode/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::Register;
use crate::{value::object, Value};
use crate::{parser::identifiers::Identifier, value::object, Value};

#[derive(Clone, Copy, Debug)]
pub struct VariableHandle(usize);
Expand Down Expand Up @@ -151,6 +151,11 @@ pub enum Instruction {
Throw {
value: Register,
},
MemberAccessWithIdentifier {
base: Register,
identifier: Identifier,
dst: Register,
},
CreateDataPropertyOrThrow {
object: Register,
property_key: object::PropertyKey,
Expand Down
13 changes: 13 additions & 0 deletions crates/js/src/bytecode/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ impl Vm {
let value = self.register(*value).clone().get_value()?;
return Err(Exception::new(value));
},
Instruction::MemberAccessWithIdentifier {
base,
identifier,
dst,
} => {
// https://262.ecma-international.org/14.0/#sec-property-accessors-runtime-semantics-evaluation
let base_value = self.register(*base).get_value()?;
let result = Value::evaluate_property_access_with_identifier_key(
base_value,
identifier.clone(),
);
self.set_register(*dst, result.into());
},
other => todo!("Implement instruction {other:?}"),
}

Expand Down
21 changes: 15 additions & 6 deletions crates/js/src/parser/expressions/member.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! <https://262.ecma-international.org/14.0/#prod-MemberExpression>
use crate::{
bytecode::{self, CompileToBytecode},
parser::{
Expand All @@ -9,6 +10,7 @@ use crate::{

use super::{parse_primary_expression, Expression};

/// <https://262.ecma-international.org/14.0/#prod-MemberExpression>
#[derive(Clone, Debug)]
pub struct MemberExpression {
/// The element whose member is being accessed
Expand All @@ -26,6 +28,7 @@ pub enum Member {
}

impl MemberExpression {
/// <https://262.ecma-international.org/14.0/#prod-MemberExpression>
pub fn parse<const YIELD: bool, const AWAIT: bool>(
tokenizer: &mut Tokenizer<'_>,
) -> Result<Expression, SyntaxError> {
Expand Down Expand Up @@ -69,13 +72,19 @@ impl CompileToBytecode for MemberExpression {
type Result = bytecode::Register;

fn compile(&self, builder: &mut bytecode::ProgramBuilder) -> Self::Result {
_ = builder;
_ = self.base;

// https://262.ecma-international.org/14.0/#sec-property-accessors-runtime-semantics-evaluation
let base = self.base.compile(builder);
match &self.member {
Member::Identifier(ident) => _ = ident,
Member::Bracket(bracket) => _ = bracket,
Member::Identifier(ident) => {
let value = builder
.get_current_block()
.member_access_with_identifier(base, ident.clone());
value
},
Member::Bracket(bracket) => {
_ = bracket;
todo!("compile member expression");
},
}
todo!("compile member expression")
}
}
8 changes: 8 additions & 0 deletions crates/js/src/parser/identifiers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! <https://262.ecma-international.org/14.0/#sec-identifiers>
use core::fmt;

use super::{
tokenization::{GoalSymbol, SkipLineTerminators, Token, Tokenizer},
SyntaxError,
Expand Down Expand Up @@ -141,3 +143,9 @@ pub(crate) fn parse_identifier_reference<const YIELD: bool, const AWAIT: bool>(
Err(tokenizer.syntax_error("expected identifier"))
}
}

impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
22 changes: 21 additions & 1 deletion crates/js/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ pub use object::Object;
pub use reference_record::{ReferenceRecord, ValueOrReference};
pub use symbol::Symbol;

use crate::bytecode::{Exception, ThrowCompletionOr};
use crate::{
bytecode::{Exception, ThrowCompletionOr},
parser::identifiers::Identifier,
};

const SPEC_CANNOT_FAIL: &str =
"This operation cannot fail according to the specification (indicated by '!')";
Expand Down Expand Up @@ -453,6 +456,23 @@ impl Value {
},
}
}

/// <https://262.ecma-international.org/14.0/#sec-evaluate-property-access-with-identifier-key>
#[must_use]
pub fn evaluate_property_access_with_identifier_key(
base_value: Self,
identifier: Identifier,
) -> ReferenceRecord {
// 1. Let propertyNameString be StringValue of identifierName.
let property_name_string = identifier.to_string();

// 2. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyNameString,
// [[Strict]]: strict, [[ThisValue]]: empty }.
ReferenceRecord {
base: base_value,
referenced_name: property_name_string,
}
}
}

/// <https://262.ecma-international.org/14.0/#sec-evaluatestringornumericbinaryexpression>
Expand Down
4 changes: 2 additions & 2 deletions crates/js/src/value/reference_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use super::{object::PropertyKey, Value};
/// <https://262.ecma-international.org/14.0/#sec-reference-record-specification-type>
#[derive(Clone, Debug)]
pub struct ReferenceRecord {
base: Value,
referenced_name: String,
pub base: Value,
pub referenced_name: String,
}

#[derive(Clone, Debug)]
Expand Down

0 comments on commit abb0d2d

Please sign in to comment.