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: prepare for refutable patterns #671

Merged
merged 1 commit into from
Jan 11, 2025
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
16 changes: 13 additions & 3 deletions package/origlang-ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,24 @@ pub struct RootAst {
pub statement: Vec<Statement>,
}

/// 分岐を含まない任意のパターン
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum AtomicPattern {
pub enum SinglePattern {
Discard,
Bind(Identifier),
Tuple(Vec<Self>),
// TODO: 定数パターンやガード付きパターンを記述できるようにする
}

impl Display for AtomicPattern {
impl SinglePattern {
// 将来実装するので今は黙らせる
#[expect(clippy::must_use_candidate, clippy::missing_const_for_fn)]
pub fn is_irrefutable_with_scrutinee_type_information(&self) -> bool {
true
}
}

impl Display for SinglePattern {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Discard => f.write_str("_"),
Expand All @@ -44,7 +54,7 @@ pub enum Statement {
expression: Expression,
},
VariableDeclaration {
pattern: AtomicPattern,
pattern: SinglePattern,
expression: Expression,
type_annotation: Option<TypeSignature>,
},
Expand Down
12 changes: 6 additions & 6 deletions package/origlang-parser/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use origlang_ast::{AtomicPattern, RootAst, Statement, TypeSignature};
use origlang_ast::{SinglePattern, RootAst, Statement, TypeSignature};
use origlang_lexer::token::internal::DisplayToken;
use origlang_lexer::token::Token;
use origlang_lexer::Lexer;
Expand Down Expand Up @@ -911,7 +911,7 @@ impl Parser {
}
}

fn parse_tuple_destruct_pattern(&self) -> Result<AtomicPattern, ParserError> {
fn parse_tuple_destruct_pattern(&self) -> Result<SinglePattern, ParserError> {
debug!("pattern:tuple");
self.read_and_consume_or_report_unexpected_token(&Token::SymLeftPar)?;

Expand Down Expand Up @@ -939,10 +939,10 @@ impl Parser {

self.read_and_consume_or_report_unexpected_token(&Token::SymRightPar)?;

Ok(AtomicPattern::Tuple(v))
Ok(SinglePattern::Tuple(v))
}

fn parse_atomic_pattern(&self) -> Result<AtomicPattern, ParserError> {
fn parse_atomic_pattern(&self) -> Result<SinglePattern, ParserError> {
debug!("pattern:atomic");
let it = self.lexer.peek().ok_or_else(|| {
ParserError::new(ParserErrorInner::EndOfFileError, self.lexer.last_position)
Expand All @@ -951,11 +951,11 @@ impl Parser {
match &it.data {
Token::Identifier { inner: name } => {
self.lexer.next();
Ok(AtomicPattern::Bind(name.clone()))
Ok(SinglePattern::Bind(name.clone()))
}
Token::SymUnderscore => {
self.lexer.next();
Ok(AtomicPattern::Discard)
Ok(SinglePattern::Discard)
}
Token::SymLeftPar => self.parse_tuple_destruct_pattern(),
other_token => Err(Self::create_unexpected_token_error(
Expand Down
8 changes: 4 additions & 4 deletions package/origlang-testsuite/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() {

use log::{debug, info};
use origlang_ast::after_parse::{BinaryOperatorKind, Expression};
use origlang_ast::{AtomicPattern, Comment, Identifier, RootAst, Statement, TypeSignature};
use origlang_ast::{SinglePattern, Comment, Identifier, RootAst, Statement, TypeSignature};
use origlang_ir::IntoVerbatimSequencedIR;
use origlang_ir_optimizer::lower::{EachStep, LowerStep, TheTranspiler};
use origlang_ir_optimizer::preset::NoOptimization;
Expand Down Expand Up @@ -633,7 +633,7 @@ print a
.expect("properly parsed")
.statement,
[Statement::VariableDeclaration {
pattern: AtomicPattern::Bind(Identifier::new("a".into())),
pattern: SinglePattern::Bind(Identifier::new("a".into())),
expression: Expression::Tuple {
expressions: vec![
Expression::IntLiteral {
Expand Down Expand Up @@ -764,7 +764,7 @@ print 1
assert_eq!(
Self::ast("var a = 1 << 2\n").expect("fail").statement,
[Statement::VariableDeclaration {
pattern: AtomicPattern::Bind(Identifier::new("a".into())),
pattern: SinglePattern::Bind(Identifier::new("a".into())),
expression: Expression::BinaryOperator {
lhs: Box::new(Expression::IntLiteral {
value: 1,
Expand All @@ -788,7 +788,7 @@ print 1
assert_eq!(
Self::ast("var a = 4 >> 2\n").expect("fail").statement,
[Statement::VariableDeclaration {
pattern: AtomicPattern::Bind(Identifier::new("a".into())),
pattern: SinglePattern::Bind(Identifier::new("a".into())),
expression: Expression::BinaryOperator {
lhs: Box::new(Expression::IntLiteral {
value: 4,
Expand Down
24 changes: 14 additions & 10 deletions package/origlang-typecheck/src/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub mod error;

use log::debug;
use origlang_ast::after_parse::{BinaryOperatorKind, Expression};
use origlang_ast::{AtomicPattern, Identifier, RootAst, Statement, TypeSignature};
use origlang_ast::{SinglePattern, Identifier, RootAst, Statement, TypeSignature};
use origlang_typesystem_model::{
AssignableQueryAnswer, Type, TypedExpression, TypedIntLiteral, TypedRootAst, TypedStatement,
};
Expand Down Expand Up @@ -250,12 +250,16 @@ impl TryIntoTypeCheckedForm for Expression {

fn handle_atomic_pattern(
expr: TypedExpression,
element_binding: &AtomicPattern,
element_binding: &SinglePattern,
checker: &TypeChecker,
) -> Result<Vec<TypedStatement>, TypeCheckError> {
if !element_binding.is_irrefutable_with_scrutinee_type_information() {
return Err(TypeCheckError::RefutablePattern)
}

match element_binding {
AtomicPattern::Discard => Ok(vec![TypedStatement::EvalAndForget { expression: expr }]),
AtomicPattern::Bind(identifier) => {
SinglePattern::Discard => Ok(vec![TypedStatement::EvalAndForget { expression: expr }]),
SinglePattern::Bind(identifier) => {
checker
.ctx
.borrow_mut()
Expand All @@ -266,7 +270,7 @@ fn handle_atomic_pattern(
expression: expr,
}])
}
AtomicPattern::Tuple(tp) => desugar_recursive_pattern_match(tp, expr, checker),
SinglePattern::Tuple(tp) => desugar_recursive_pattern_match(tp, expr, checker),
}
}

Expand All @@ -276,7 +280,7 @@ enum RecursivePatternMatchDesugarStrategy {
}

fn desugar_recursive_pattern_match(
outer_destruction: &[AtomicPattern],
outer_destruction: &[SinglePattern],
mut rhs: TypedExpression,
checker: &TypeChecker,
) -> Result<Vec<TypedStatement>, TypeCheckError> {
Expand All @@ -289,7 +293,7 @@ fn desugar_recursive_pattern_match(
let Type::Tuple(tuple_element_types) = tp else {
debug!("non-tuple expression");
break Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
pattern: SinglePattern::Tuple(outer_destruction.to_vec()),
expression: TypedExpression::Variable {
ident,
tp: tp.clone(),
Expand Down Expand Up @@ -318,7 +322,7 @@ fn desugar_recursive_pattern_match(

debug!("tuple arity mismatch");
break Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
pattern: SinglePattern::Tuple(outer_destruction.to_vec()),
expression: TypedExpression::Variable {
ident,
tp: Type::tuple(tuple_element_types.clone()),
Expand Down Expand Up @@ -420,7 +424,7 @@ fn desugar_recursive_pattern_match(
other => {
debug!("unsupported expression");
break Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
pattern: SinglePattern::Tuple(outer_destruction.to_vec()),
expr_type: other.actual_type(),
expression: other,
});
Expand All @@ -431,7 +435,7 @@ fn desugar_recursive_pattern_match(

fn extract_pattern(
expr: TypedExpression,
pattern: &AtomicPattern,
pattern: &SinglePattern,
type_annotation: Option<TypeSignature>,
checker: &TypeChecker,
) -> Result<Vec<TypedStatement>, TypeCheckError> {
Expand Down
6 changes: 4 additions & 2 deletions package/origlang-typecheck/src/type_check/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use origlang_ast::after_parse::BinaryOperatorKind;
use origlang_ast::{AtomicPattern, Identifier, TypeSignature};
use origlang_ast::{SinglePattern, Identifier, TypeSignature};
use origlang_typesystem_model::Type;
use origlang_typesystem_model::TypedExpression;
use thiserror::Error;
Expand Down Expand Up @@ -40,8 +40,10 @@ pub enum TypeCheckError {
UnknownType { name: TypeSignature },
#[error("pattern {pattern} may not be satisfied where the expression has type of {expr_type}")]
UnsatisfiablePattern {
pattern: AtomicPattern,
pattern: SinglePattern,
expression: TypedExpression,
expr_type: Type,
},
#[error("cannot use this pattern at here because it is not exhaustive")]
RefutablePattern,
}