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

New constant declration syntax #1062

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
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
Loading