Skip to content

Commit

Permalink
Merge pull request #671 from KisaragiEffective/feat/refutable-pattern…
Browse files Browse the repository at this point in the history
…/prepare
  • Loading branch information
KisaragiEffective authored Jan 11, 2025
2 parents 44c6ddc + e9157a5 commit 80416e0
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 25 deletions.
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,
}

0 comments on commit 80416e0

Please sign in to comment.