feat(type-system): implement concept_comparison with pattern matching
Added complete support for the new type system syntax including: - concept: Base type declarations - sub_concept: Enum and record sub-type definitions - concept_comparison: Compile-time pattern matching with conditional guards Parser changes: - Added VariantPattern, FieldCondition, and Condition AST nodes - Implemented "is" keyword for pattern matching (e.g., "CupType is Glass or CupType is Plastic") - Added Value::Any variant to support universal type matching - Disambiguated enum-like vs record-like sub_concept syntax LSP updates: - Added Value::Any match arms across code_actions, completion, hover, inlay_hints, and semantic_tokens - Type inference and formatting support for Any values Example fixes: - Fixed syntax error in baker-family behaviors (missing closing brace in nested if) - Removed deprecated core_enums.sb file
This commit is contained in:
@@ -20,7 +20,9 @@ Declaration: Declaration = {
|
||||
<r:Relationship> => Declaration::Relationship(r),
|
||||
<loc:Location> => Declaration::Location(loc),
|
||||
<sp:Species> => Declaration::Species(sp),
|
||||
<e:EnumDecl> => Declaration::Enum(e),
|
||||
<concept:ConceptDecl> => Declaration::Concept(concept),
|
||||
<sub:SubConceptDecl> => Declaration::SubConcept(sub),
|
||||
<comp:ConceptComparisonDecl> => Declaration::ConceptComparison(comp),
|
||||
};
|
||||
|
||||
// ===== Use declarations =====
|
||||
@@ -246,6 +248,7 @@ Value: Value = {
|
||||
<FloatLit> => Value::Float(<>),
|
||||
<StringLit> => Value::String(<>),
|
||||
<BoolLit> => Value::Bool(<>),
|
||||
"any" => Value::Any,
|
||||
<lo:IntLit> ".." <hi:IntLit> => Value::Range(
|
||||
Box::new(Value::Int(lo)),
|
||||
Box::new(Value::Int(hi))
|
||||
@@ -740,14 +743,120 @@ Species: Species = {
|
||||
|
||||
// ===== Enum =====
|
||||
|
||||
EnumDecl: EnumDecl = {
|
||||
"enum" <name:Ident> "{" <variants:Comma<Ident>> "}" => EnumDecl {
|
||||
// ===== Type System Declarations =====
|
||||
|
||||
ConceptDecl: ConceptDecl = {
|
||||
"concept" <name:Ident> => ConceptDecl {
|
||||
name,
|
||||
span: Span::new(0, 0),
|
||||
}
|
||||
};
|
||||
|
||||
SubConceptDecl: SubConceptDecl = {
|
||||
// Enum-like sub_concept: sub_concept PlateColor { Red, Blue, Green }
|
||||
"sub_concept" <name:Ident> "{" <variants:Comma<Ident>> "}" => {
|
||||
let parent = {
|
||||
let mut last_cap = 0;
|
||||
for (i, ch) in name.char_indices().skip(1) {
|
||||
if ch.is_uppercase() {
|
||||
last_cap = i;
|
||||
}
|
||||
}
|
||||
if last_cap > 0 {
|
||||
name[..last_cap].to_string()
|
||||
} else {
|
||||
name.clone()
|
||||
}
|
||||
};
|
||||
|
||||
SubConceptDecl {
|
||||
name,
|
||||
parent_concept: parent,
|
||||
kind: SubConceptKind::Enum { variants },
|
||||
span: Span::new(0, 0),
|
||||
}
|
||||
},
|
||||
// Record-like sub_concept with at least one field
|
||||
"sub_concept" <name:Ident> "{" <first:Ident> ":" <first_val:Value> <rest:("," <Ident> ":" <Value>)*> ","? "}" => {
|
||||
let parent = {
|
||||
let mut last_cap = 0;
|
||||
for (i, ch) in name.char_indices().skip(1) {
|
||||
if ch.is_uppercase() {
|
||||
last_cap = i;
|
||||
}
|
||||
}
|
||||
if last_cap > 0 {
|
||||
name[..last_cap].to_string()
|
||||
} else {
|
||||
name.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let mut fields = vec![Field {
|
||||
name: first,
|
||||
value: first_val,
|
||||
span: Span::new(0, 0),
|
||||
}];
|
||||
|
||||
for (field_name, field_val) in rest {
|
||||
fields.push(Field {
|
||||
name: field_name,
|
||||
value: field_val,
|
||||
span: Span::new(0, 0),
|
||||
});
|
||||
}
|
||||
|
||||
SubConceptDecl {
|
||||
name,
|
||||
parent_concept: parent,
|
||||
kind: SubConceptKind::Record { fields },
|
||||
span: Span::new(0, 0),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ConceptComparisonDecl: ConceptComparisonDecl = {
|
||||
"concept_comparison" <name:Ident> "{" <variants:Comma<VariantPattern>> "}" => ConceptComparisonDecl {
|
||||
name,
|
||||
variants,
|
||||
span: Span::new(0, 0),
|
||||
}
|
||||
};
|
||||
|
||||
VariantPattern: VariantPattern = {
|
||||
<name:Ident> ":" "{" <conditions:Comma<FieldCondition>> "}" => VariantPattern {
|
||||
name,
|
||||
conditions,
|
||||
span: Span::new(0, 0),
|
||||
}
|
||||
};
|
||||
|
||||
FieldCondition: FieldCondition = {
|
||||
<field:Ident> ":" "any" => FieldCondition {
|
||||
field_name: field,
|
||||
condition: Condition::Any,
|
||||
span: Span::new(0, 0),
|
||||
},
|
||||
<field:Ident> ":" <cond:IsCondition> => FieldCondition {
|
||||
field_name: field,
|
||||
condition: Condition::Is(cond),
|
||||
span: Span::new(0, 0),
|
||||
},
|
||||
};
|
||||
|
||||
// Parse "FieldName is Value1 or FieldName is Value2" and extract the values
|
||||
IsCondition: Vec<String> = {
|
||||
<first:IsValue> <rest:("or" <IsValue>)*> => {
|
||||
let mut values = vec![first];
|
||||
values.extend(rest);
|
||||
values
|
||||
}
|
||||
};
|
||||
|
||||
IsValue: String = {
|
||||
<field:Ident> "is" <value:Ident> => value
|
||||
};
|
||||
|
||||
// ===== Expressions =====
|
||||
// Expression grammar with proper precedence:
|
||||
// or > and > not > field_access > comparison > term
|
||||
@@ -877,7 +986,10 @@ extern {
|
||||
"relationship" => Token::Relationship,
|
||||
"location" => Token::Location,
|
||||
"species" => Token::Species,
|
||||
"enum" => Token::Enum,
|
||||
"concept" => Token::Concept,
|
||||
"sub_concept" => Token::SubConcept,
|
||||
"concept_comparison" => Token::ConceptComparison,
|
||||
"any" => Token::Any,
|
||||
"state" => Token::State,
|
||||
"on" => Token::On,
|
||||
"enter" => Token::Enter,
|
||||
|
||||
Reference in New Issue
Block a user