Browse Source

Method parsing (#339)

pull/343/head
Victor Tuekam 5 years ago committed by GitHub
parent
commit
a9372b7779
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 131
      boa/src/syntax/parser/mod.rs
  2. 53
      boa/src/syntax/parser/tests.rs

131
boa/src/syntax/parser/mod.rs

@ -1637,17 +1637,20 @@ impl<'a> Parser<'a> {
Ok(Node::Object(elements)) Ok(Node::Object(elements))
} }
fn get_object_property_name(&mut self) -> Result<String, ParseError> {
let to_string = |token: &Token| match &token.kind {
TokenKind::Identifier(name) => name.clone(),
TokenKind::NumericLiteral(n) => format!("{}", n),
TokenKind::StringLiteral(s) => s.clone(),
_ => unimplemented!("{:?}", token.kind),
};
self.next_skip_lineterminator()
.map(to_string)
.ok_or(ParseError::AbruptEnd)
}
/// <https://tc39.es/ecma262/#prod-PropertyDefinition> /// <https://tc39.es/ecma262/#prod-PropertyDefinition>
fn read_property_definition(&mut self) -> Result<PropertyDefinition, ParseError> { fn read_property_definition(&mut self) -> Result<PropertyDefinition, ParseError> {
fn to_string(kind: &TokenKind) -> String {
match kind {
TokenKind::Identifier(name) => name.clone(),
TokenKind::NumericLiteral(n) => format!("{}", n),
TokenKind::StringLiteral(s) => s.clone(),
_ => unimplemented!("{:?}", kind),
}
}
if self if self
.next_if_skip_lineterminator(TokenKind::Punctuator(Punctuator::Spread)) .next_if_skip_lineterminator(TokenKind::Punctuator(Punctuator::Spread))
.is_some() .is_some()
@ -1656,11 +1659,7 @@ impl<'a> Parser<'a> {
return Ok(PropertyDefinition::SpreadObject(node)); return Ok(PropertyDefinition::SpreadObject(node));
} }
let prop_name = self let prop_name = self.get_object_property_name()?;
.next_skip_lineterminator()
.map(|tok| to_string(&tok.kind))
.ok_or(ParseError::AbruptEnd)?;
if self if self
.next_if_skip_lineterminator(TokenKind::Punctuator(Punctuator::Colon)) .next_if_skip_lineterminator(TokenKind::Punctuator(Punctuator::Colon))
.is_some() .is_some()
@ -1669,55 +1668,15 @@ impl<'a> Parser<'a> {
return Ok(PropertyDefinition::Property(prop_name, val)); return Ok(PropertyDefinition::Property(prop_name, val));
} }
// TODO: Split into separate function: read_property_method_definition
if self if self
.next_if_skip_lineterminator(TokenKind::Punctuator(Punctuator::OpenParen)) .next_if_skip_lineterminator(TokenKind::Punctuator(Punctuator::OpenParen))
.is_some() .is_some()
|| ["get", "set"].contains(&prop_name.as_str())
{ {
let params = self.read_formal_parameters()?; let method_identifer = prop_name;
return self.read_property_method_definition(method_identifer.as_str());
self.expect(
TokenKind::Punctuator(Punctuator::OpenBlock),
Some("property method definition"),
)?;
let body = self.read_block()?;
return Ok(PropertyDefinition::MethodDefinition(
MethodDefinitionKind::Ordinary,
prop_name,
Node::FunctionDecl(None, params, Box::new(body)),
));
} }
// TODO need to revisit this
// if let TokenKind::Identifier(name) = tok.kind {
// if name == "get" || name == "set" {
// let may_identifier = self.peek_skip_lineterminator();
// if may_identifier.is_some()
// && matches!(may_identifier.unwrap().kind, TokenKind::Identifier(_))
// {
// let f = self.read_function_expression()?;
// let func_name = if let NodeBase::FunctionExpr(ref name, _, _) = f.base {
// name.clone().unwrap()
// } else {
// panic!()
// };
// return Ok(PropertyDefinition::MethodDefinition(
// if name == "get" {
// MethodDefinitionKind::Get
// } else {
// MethodDefinitionKind::Set
// },
// func_name,
// f,
// ));
// }
// }
// return Ok(PropertyDefinition::IdentifierReference(name));
// }
let pos = self let pos = self
.cursor .cursor
.peek(0) .peek(0)
@ -1728,4 +1687,62 @@ impl<'a> Parser<'a> {
Some(pos), Some(pos),
)) ))
} }
/// <https://tc39.es/ecma262/#prod-MethodDefinition>
fn read_property_method_definition(
&mut self,
identifier: &str,
) -> Result<PropertyDefinition, ParseError> {
let (methodkind, prop_name, params) = match identifier {
"get" | "set" => {
let prop_name = self.get_object_property_name()?;
self.expect(
TokenKind::Punctuator(Punctuator::OpenParen),
Some("property method definition"),
)?;
let first_param = self
.peek_skip_lineterminator()
.expect("current token disappeared")
.clone();
let params = self.read_formal_parameters()?;
if identifier == "get" {
if !params.is_empty() {
return Err(ParseError::Unexpected(
first_param,
Some("getter functions must have no arguments"),
));
}
(MethodDefinitionKind::Get, prop_name, params)
} else {
if params.len() != 1 {
return Err(ParseError::Unexpected(
first_param,
Some("setter functions must have one argument"),
));
}
(MethodDefinitionKind::Set, prop_name, params)
}
}
prop_name => {
let params = self.read_formal_parameters()?;
(
MethodDefinitionKind::Ordinary,
prop_name.to_string(),
params,
)
}
};
self.expect(
TokenKind::Punctuator(Punctuator::OpenBlock),
Some("property method definition"),
)?;
let body = self.read_block()?;
Ok(PropertyDefinition::MethodDefinition(
methodkind,
prop_name,
Node::FunctionDecl(None, params, Box::new(body)),
))
}
} }

53
boa/src/syntax/parser/tests.rs

@ -116,6 +116,59 @@ fn check_object_short_function_arguments() {
)])], )])],
); );
} }
#[test]
fn check_object_getter() {
let object_properties = vec![
PropertyDefinition::Property(String::from("a"), Node::Const(Const::Bool(true))),
PropertyDefinition::MethodDefinition(
MethodDefinitionKind::Get,
String::from("b"),
Node::FunctionDecl(None, Vec::new(), Box::new(Node::StatementList(Vec::new()))),
),
];
check_parser(
"const x = {
a: true,
get b() {}
};
",
&[Node::ConstDecl(vec![(
String::from("x"),
Node::Object(object_properties),
)])],
);
}
#[test]
fn check_object_setter() {
let object_properties = vec![
PropertyDefinition::Property(String::from("a"), Node::Const(Const::Bool(true))),
PropertyDefinition::MethodDefinition(
MethodDefinitionKind::Set,
String::from("b"),
Node::FunctionDecl(
None,
vec![FormalParameter::new(String::from("test"), None, false)],
Box::new(Node::StatementList(Vec::new())),
),
),
];
check_parser(
"const x = {
a: true,
set b(test) {}
};
",
&[Node::ConstDecl(vec![(
String::from("x"),
Node::Object(object_properties),
)])],
);
}
#[test] #[test]
fn check_array() { fn check_array() {
use crate::syntax::ast::constant::Const; use crate::syntax::ast::constant::Const;

Loading…
Cancel
Save