Skip to content
Draft
18 changes: 9 additions & 9 deletions compiler/hash-ast-utils/src/pretty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ where
&mut self,
node: ast::AstNodeRef<ast::Declaration>,
) -> Result<Self::DeclarationRet, Self::Error> {
let ast::Declaration { pat, ty, value } = node.body();
let ast::Declaration { pat, ty, value, is_constant } = node.body();

self.visit_pat(pat.ast_ref())?;

Expand All @@ -168,7 +168,12 @@ where
}

// Visit the initialiser
self.write("= ")?;
if *is_constant {
self.write(": ")?;
} else {
self.write("= ")?;
}

self.visit_expr(value.ast_ref())
}

Expand Down Expand Up @@ -1140,13 +1145,9 @@ where
&mut self,
node: ast::AstNodeRef<ast::AccessExpr>,
) -> Result<Self::AccessExprRet, Self::Error> {
let ast::AccessExpr { subject, property, kind } = node.body();
let ast::AccessExpr { subject, property } = node.body();
self.visit_expr(subject.ast_ref())?;

match kind {
ast::AccessKind::Namespace => self.write("::")?,
ast::AccessKind::Property => self.write(".")?,
}
self.write(".")?;

self.visit_property_kind(property.ast_ref())
}
Expand Down Expand Up @@ -1432,7 +1433,6 @@ where
Ty,
Pat,
Visibility,
AccessKind,
Mutability,
RefKind,
UnOp,
Expand Down
12 changes: 0 additions & 12 deletions compiler/hash-ast-utils/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,22 +184,10 @@ impl AstVisitor for AstTreePrinter {
vec![
TreeNode::branch("subject", vec![subject]),
TreeNode::branch("property", vec![property]),
TreeNode::leaf(labelled("kind", node.kind, "\"")),
],
))
}

type AccessKindRet = TreeNode;
fn visit_access_kind(
&self,
node: ast::AstNodeRef<ast::AccessKind>,
) -> Result<Self::AccessKindRet, Self::Error> {
match node.body() {
ast::AccessKind::Property => Ok(TreeNode::leaf("property")),
ast::AccessKind::Namespace => Ok(TreeNode::leaf("namespace")),
}
}

type RefExprRet = TreeNode;
fn visit_ref_expr(
&self,
Expand Down
26 changes: 4 additions & 22 deletions compiler/hash-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,7 @@ define_tree! {
pub enum Pat {
/// An access pattern is one that denotes the access of a property from
/// another pattern. This is used to denote namespace accesses like
/// `a::b::c`
/// `a.b.c`
Access(AccessPat),

/// A simple binding pattern, assign some value to the name of the pattern
Expand Down Expand Up @@ -1269,6 +1269,9 @@ define_tree! {
/// Any value that is assigned to the binding, simply
/// an expression.
pub value: Child!(Expr),

/// Whether the declaration is constant or not.
pub is_constant: bool,
}

/// Unary operators that are defined within the core of the language.
Expand Down Expand Up @@ -1974,25 +1977,6 @@ define_tree! {
pub args: Children!(ExprArg),
}

/// A the kind of access an [AccessExpr] has
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[node]
pub enum AccessKind {
/// A namespace access, i.e. `a::b`
Namespace,
/// A property access, i.e. `a.b`
Property,
}

impl Display for AccessKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AccessKind::Namespace => write!(f, "namespace"),
AccessKind::Property => write!(f, "property"),
}
}
}

/// The kind of property that's being accessed, either being
/// named or numeric, e.g `foo.x`, `foo.1`, etc.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand All @@ -2013,8 +1997,6 @@ define_tree! {
pub subject: Child!(Expr),
/// The property of the subject to access.
pub property: Child!(PropertyKind),
/// The kind of access, either namespacing or property
pub kind: AccessKind,
}

/// A typed expression, e.g. `foo as int`.
Expand Down
79 changes: 45 additions & 34 deletions compiler/hash-parser/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ impl<'s> AstGen<'s> {
// pattern which is then followed by a `:` to denote that this is a
// declaration.
if self.begins_pat() {
let pat = self.parse_singular_pat()?;
self.parse_token(TokenKind::Colon)?;
let decl = self.parse_declaration(pat)?;

let decl = self.parse_declaration()?;
let expr = self.node_with_joined_span(Expr::Declaration(decl), start);
let semi = maybe_eat_semi(self);
return Ok(Some((semi, expr)));
Expand Down Expand Up @@ -365,7 +362,6 @@ impl<'s> AstGen<'s> {
subject = match token.kind {
// Property access or method call
TokenKind::Dot => self.parse_property_access(subject, subject_span)?,
TokenKind::Access => self.parse_ns_access(subject, subject_span)?,
TokenKind::Lt => match self.maybe_parse_implicit_call(subject, subject_span) {
(subject, true) => subject,
// Essentially break because the type_args failed
Expand Down Expand Up @@ -581,19 +577,53 @@ impl<'s> AstGen<'s> {
/// ```text
/// some_var: f64 = ...;
/// ^^^^^^^^ ^^^ ^^^─────┐
/// pattern type the right hand-side expr
/// pattern annotation the right hand-side expr
/// ```
pub(crate) fn parse_declaration(&mut self, pat: AstNode<Pat>) -> ParseResult<Declaration> {
// Attempt to parse an optional type...
pub(crate) fn parse_declaration(&mut self) -> ParseResult<Declaration> {
let pat = self.parse_singular_pat()?;
let mut is_constant = false;

// Figure out if this declaration has an annotation or not...
let ty = match self.peek_kind() {
Some(TokenKind::Eq) => None,
_ => Some(self.parse_ty()?),
Some(TokenKind::Access) => {
self.skip_fast(TokenKind::Access); // `::`
is_constant = true;
None
}
_ => {
self.parse_token(TokenKind::Colon)?; // `:`

if self.peek_kind() == Some(TokenKind::Eq) {
self.skip_fast(TokenKind::Eq); // `=`
None
} else {
Some(self.parse_ty()?)
}
}
};

// Now parse the initialiser...
self.parse_token(TokenKind::Eq)?;
if !is_constant && ty.is_some() {
match self.peek_kind() {
Some(TokenKind::Eq) => {
self.skip_fast(TokenKind::Eq); // `=`
}
Some(TokenKind::Colon) => {
self.skip_fast(TokenKind::Colon); // `=`
is_constant = true;
}
tok => {
return self.err(
ParseErrorKind::UnExpected,
ExpectedItem::Colon | ExpectedItem::Eq,
tok,
)
}
}
}

let value = self.parse_expr_with_precedence(0)?;
Ok(Declaration { pat, ty, value })
Ok(Declaration { pat, ty, value, is_constant })
}

/// Given a initial left-hand side expression, attempt to parse a
Expand Down Expand Up @@ -636,8 +666,7 @@ impl<'s> AstGen<'s> {
}
}

/// Parse a property access expression, in other words an [AccessExpr] with
/// the [AccessKind::Property] variant.
/// Parse a property access expression, in other words an [AccessExpr].
pub(crate) fn parse_property_access(
&mut self,
subject: AstNode<Expr>,
Expand Down Expand Up @@ -675,32 +704,14 @@ impl<'s> AstGen<'s> {
let property = self.node_with_span(PropertyKind::NumericField(value), token.span);

return Ok(self.node_with_joined_span(
Expr::Access(AccessExpr { subject, property, kind: AccessKind::Property }),
Expr::Access(AccessExpr { subject, property }),
subject_span,
));
}
}

let property = self.parse_named_field(ParseErrorKind::ExpectedPropertyAccess)?;
Ok(self.node_with_joined_span(
Expr::Access(AccessExpr { subject, property, kind: AccessKind::Property }),
subject_span,
))
}

/// Parse a [AccessExpr] with a `namespace` access kind.
pub(crate) fn parse_ns_access(
&mut self,
subject: AstNode<Expr>,
subject_span: ByteRange,
) -> ParseResult<AstNode<Expr>> {
self.skip_fast(TokenKind::Access); // `::`

let property = self.parse_named_field(ParseErrorKind::ExpectedName)?;
Ok(self.node_with_joined_span(
Expr::Access(AccessExpr { subject, property, kind: AccessKind::Namespace }),
subject_span,
))
Ok(self.node_with_joined_span(Expr::Access(AccessExpr { subject, property }), subject_span))
}

/// Function to either parse an expression that is wrapped in parentheses or
Expand Down
22 changes: 12 additions & 10 deletions compiler/hash-parser/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ impl<'s> AstGen<'s> {
}
// An access pattern which accesses the `subject` with a particular `property`
// denotes with a name.
TokenKind::Access => {
self.skip_fast(TokenKind::Access); // `::`
TokenKind::Dot => {
self.skip_fast(TokenKind::Dot); // `.`
let property = self.parse_name()?;
self.node_with_joined_span(Pat::Access(AccessPat { subject, property }), span)
}
Expand Down Expand Up @@ -554,9 +554,11 @@ impl<'s> AstGen<'s> {
}

fn peek_pat(&self) -> bool {
macro_rules! peek_colon(
// This is a macro that is used to simplify the lookahead for the pattern
// boundary, which can either be a `:` or a `::` token.
macro_rules! peek_pat_boundary(
() => {
matches!(self.peek_kind(), Some(TokenKind::Colon))
matches!(self.peek_kind(), Some(TokenKind::Colon | TokenKind::Access))
}
);

Expand All @@ -575,7 +577,7 @@ impl<'s> AstGen<'s> {
&& kind.is_range_lit()
{
self.skip_fast(kind);
peek_colon!()
peek_pat_boundary!()
} else {
false
}
Expand All @@ -587,12 +589,12 @@ impl<'s> AstGen<'s> {
// Other general literal patterns.
Some(kind) if kind.is_lit() => {
self.skip_fast(kind);
peek_colon!()
peek_pat_boundary!()
}
// Module, Array, Tuple patterns.
Some(TokenKind::Tree(_, _)) => {
self.skip_token();
peek_colon!()
peek_pat_boundary!()
}
// Identifier or constructor pattern.
Some(ident @ TokenKind::Ident(_)) => {
Expand All @@ -606,8 +608,8 @@ impl<'s> AstGen<'s> {
TokenKind::Tree(Delimiter::Paren, _) => self.skip_token(),
// Handle the `access` pattern case. We're looking for the next
// three tokens to be `::Ident`
TokenKind::Access => {
self.skip_fast(TokenKind::Access);
TokenKind::Dot => {
self.skip_fast(TokenKind::Dot); // `.`

match self.peek_kind() {
Some(ident @ TokenKind::Ident(_)) => {
Expand All @@ -620,7 +622,7 @@ impl<'s> AstGen<'s> {
}
}

peek_colon!()
peek_pat_boundary!()
}
// This is the case for a bind that has a visibility modifier at the beginning. In
// this scenario, it can be followed by a `mut` modifier and then a identifier or
Expand Down
4 changes: 2 additions & 2 deletions compiler/hash-parser/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ impl<'s> AstGen<'s> {
Ty::Fn(FnTy { params: self.make_params(params, ParamOrigin::Fn), return_ty })
}

TokenKind::Access => {
self.skip_fast(TokenKind::Access);
TokenKind::Dot => {
self.skip_fast(TokenKind::Dot); // .

Ty::Access(AccessTy {
subject: self.node_with_joined_span(ty, span),
Expand Down
42 changes: 18 additions & 24 deletions compiler/hash-semantics/src/passes/resolution/exprs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,27 +246,24 @@ impl<E: SemanticEnv> ResolutionPass<'_, E> {
&self,
node: AstNodeRef<'a, ast::AccessExpr>,
) -> SemanticResult<Option<AstPath<'a>>> {
match node.kind {
ast::AccessKind::Namespace => match node.property.body() {
ast::PropertyKind::NamedField(name) => {
let mut root =
self.expr_as_ast_path(node.body.subject.ast_ref())?.ok_or_else(|| {
SemanticError::InvalidNamespaceSubject { location: node.span() }
})?;
root.push(AstPathComponent {
name: *name,
name_node_id: node.property.id(),
args: Node::at(vec![], NodeOrigin::Given(node.id())),
node_id: node.id(),
});
Ok(Some(root))
}
ast::PropertyKind::NumericField(_) => {
// Should have been caught at semantics
panic_on_span!(node.span(), "Namespace followed by numeric field found")
}
},
ast::AccessKind::Property => Ok(None),
match node.property.body() {
ast::PropertyKind::NamedField(name) => {
let mut root =
self.expr_as_ast_path(node.body.subject.ast_ref())?.ok_or_else(|| {
SemanticError::InvalidNamespaceSubject { location: node.span() }
})?;
root.push(AstPathComponent {
name: *name,
name_node_id: node.property.id(),
args: Node::at(vec![], NodeOrigin::Given(node.id())),
node_id: node.id(),
});
Ok(Some(root))
}
ast::PropertyKind::NumericField(_) => {
// Should have been caught at semantics
panic_on_span!(node.span(), "Namespace followed by numeric field found")
}
}
}

Expand Down Expand Up @@ -422,9 +419,6 @@ impl<E: SemanticEnv> ResolutionPass<'_, E> {
self.make_term_from_resolved_ast_path(&resolved_path, node.id())
}
None => {
// Namespace handled above.
assert!(matches!(node.kind, ast::AccessKind::Property));

let subject = self.make_term_from_ast_expr(node.subject.ast_ref())?;
let field = match node.property.body() {
ast::PropertyKind::NamedField(name) => ParamIndex::Name(*name),
Expand Down
Loading