Skip to content

Commit

Permalink
Change parser for dynamic class|enum Type
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniosarosi committed Feb 13, 2025
1 parent bdcf643 commit ab78adf
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 53 deletions.
26 changes: 25 additions & 1 deletion engine/baml-lib/baml-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ pub fn validate_type_builder_entries(
dyn_type.span.to_owned(),
);

// TODO: Not necessary, the parser also does this now that we've
// change "dynamic ClassName" to "dynamic class ClassName".
dyn_type.is_dynamic_type_def = true;

// Resolve dynamic definition. It either appends to a
Expand All @@ -245,7 +247,18 @@ pub fn validate_type_builder_entries(
diagnostics.push_error(DatamodelError::new_validation_error(
&format!(
"Type '{}' does not contain the `@@dynamic` attribute so it cannot be modified in a type builder block",
cls.name()
cls.name()
),
dyn_type.span.to_owned(),
));
continue;
}

if matches!(dyn_type.sub_type, ast::SubType::Enum) {
diagnostics.push_error(DatamodelError::new_validation_error(
&format!(
"Type '{}' is a class, but the dynamic block is defined as 'dynamic enum'",
cls.name()
),
dyn_type.span.to_owned(),
));
Expand All @@ -266,6 +279,17 @@ pub fn validate_type_builder_entries(
continue;
}

if matches!(dyn_type.sub_type, ast::SubType::Class) {
diagnostics.push_error(DatamodelError::new_validation_error(
&format!(
"Type '{}' is an enum, but the dynamic block is defined as 'dynamic class'",
enm.name()
),
dyn_type.span.to_owned(),
));
continue;
}

ast::Top::Enum(dyn_type)
},
TypeWalker::TypeAlias(_) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class Education {
year int
}

enum Job {
SoftwareEngineer
DataScientist
@@dynamic
}

// This function returns the dynamic class defined above.
function ExtractResume(from_text: string) -> Resume {
client "openai/gpt-4o-mini"
Expand All @@ -28,11 +34,22 @@ test ReturnDynamicClassTest {
start_date string
end_date string
}

enum Level {
Junior
Mid
Senior
}

// This `dynamic` block is used to inject new properties into the
// `@@dynamic` part of the Resume class.
dynamic Resume {
dynamic class Resume {
experience Experience[]
level Level
}

dynamic enum Job {
ProductManager
}
}
args {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ test AttemptToIntroduceInfiniteCycle {
p A
}

dynamic DynamicClass {
dynamic class DynamicClass {
cycle A
}
}
Expand All @@ -34,7 +34,7 @@ test AttemptToIntroduceInfiniteCycle {
test AttemptToMakeClassInfinitelyRecursive {
functions [TypeBuilderFn]
type_builder {
dynamic DynamicClass {
dynamic class DynamicClass {
cycle DynamicClass
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class DynamicClass {
test AttemptToMakeClassInfinitelyRecursive {
functions [TypeBuilderFn]
type_builder {
dynamic DynamicClass {
dynamic class DynamicClass {
cycle DynamicClass
}
}
Expand All @@ -25,7 +25,7 @@ test AttemptToMakeClassInfinitelyRecursive {
// --> tests/dynamic_types_internal_cycle_errors.baml:15
// |
// 14 | type_builder {
// 15 | dynamic DynamicClass {
// 15 | dynamic class DynamicClass {
// 16 | cycle DynamicClass
// 17 | }
// |
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function TypeBuilderFn(from_text: string) -> Resume {
class Foo {
foo string
}
dynamic Bar {
dynamic class Bar {
bar int
}
}
Expand All @@ -17,15 +17,15 @@ test MultipleTypeBuilderBlocks {
class Foo {
foo string
}
dynamic Bar {
dynamic class Bar {
bar int
}
}
type_builder {
class A {
a string
}
dynamic B {
dynamic class B {
b int
}
}
Expand All @@ -34,12 +34,24 @@ test MultipleTypeBuilderBlocks {
}
}

test IncompleteDynamicDef {
functions [TypeBuilderFn]
type_builder {
dynamic Bar {
bar int
}
}
args {
from_text "Test"
}
}

test IncompleteSyntax {
functions [TypeBuilderFn]
type_builder {
type

dynamic Bar {
dynamic class Bar {
bar int
}
}
Expand All @@ -56,7 +68,7 @@ test IncompleteSyntax {
// 5 | class Foo {
// 6 | foo string
// 7 | }
// 8 | dynamic Bar {
// 8 | dynamic class Bar {
// 9 | bar int
// 10 | }
// 11 | }
Expand All @@ -69,15 +81,21 @@ test IncompleteSyntax {
// 25 | class A {
// 26 | a string
// 27 | }
// 28 | dynamic B {
// 28 | dynamic class B {
// 29 | b int
// 30 | }
// 31 | }
// |
// error: Error validating: Syntax error in type builder block
// error: Error validating: Incomplete 'dynamic' type definition. Use 'dynamic class' or 'dynamic enum' to add properties to types that contain the `@@dynamic` attribute.
// --> tests/dynamic_types_parser_errors.baml:40
// |
// 39 | type_builder {
// 40 | type
// 41 |
// 40 | dynamic Bar {
// |
// error: Error validating: Syntax error in type builder block
// --> tests/dynamic_types_parser_errors.baml:52
// |
// 51 | type_builder {
// 52 | type
// 53 |
// |
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class NonDynamic {
test AttemptToModifyNonDynamicClass {
functions [TypeBuilderFn]
type_builder {
dynamic NonDynamic {
dynamic class NonDynamic {
c string
}
}
Expand All @@ -25,7 +25,7 @@ type SomeAlias = NonDynamic
test AttemptToModifyTypeAlias {
functions [TypeBuilderFn]
type_builder {
dynamic SomeAlias {
dynamic class SomeAlias {
c string
}
}
Expand All @@ -51,7 +51,7 @@ test AttemptToAddDynamicAttrInDyanmicDef {
A
@@dynamic
}
dynamic DynamicClass {
dynamic class DynamicClass {
c string
@@dynamic
}
Expand All @@ -64,10 +64,10 @@ test AttemptToAddDynamicAttrInDyanmicDef {
test AttemptToModifySameDynamicMultipleTimes {
functions [TypeBuilderFn]
type_builder {
dynamic DynamicClass {
dynamic class DynamicClass {
c string
}
dynamic DynamicClass {
dynamic class DynamicClass {
d string
}
}
Expand All @@ -83,7 +83,7 @@ test NameAlreadyExists {
a string
b string
}
dynamic DynamicClass {
dynamic class DynamicClass {
non_dynamic NonDynamic
}
}
Expand All @@ -92,19 +92,40 @@ test NameAlreadyExists {
}
}

enum DynamicEnum {
A
B
@@dynamic
}

test TypeMismatch {
functions [TypeBuilderFn]
type_builder {
dynamic class DynamicEnum {
C
}
dynamic enum DynamicClass {
c string
}
}
args {
from_text "Test"
}
}

// error: Error validating: Type 'NonDynamic' does not contain the `@@dynamic` attribute so it cannot be modified in a type builder block
// --> tests/dynamic_types_validation_errors.baml:14
// |
// 13 | type_builder {
// 14 | dynamic NonDynamic {
// 14 | dynamic class NonDynamic {
// 15 | c string
// 16 | }
// |
// error: Error validating: The `dynamic` keyword only works on classes and enums, but type 'SomeAlias' is a type alias
// --> tests/dynamic_types_validation_errors.baml:28
// |
// 27 | type_builder {
// 28 | dynamic SomeAlias {
// 28 | dynamic class SomeAlias {
// 29 | c string
// 30 | }
// |
Expand All @@ -130,7 +151,7 @@ test NameAlreadyExists {
// --> tests/dynamic_types_validation_errors.baml:54
// |
// 53 | }
// 54 | dynamic DynamicClass {
// 54 | dynamic class DynamicClass {
// 55 | c string
// 56 | @@dynamic
// 57 | }
Expand All @@ -139,7 +160,7 @@ test NameAlreadyExists {
// --> tests/dynamic_types_validation_errors.baml:70
// |
// 69 | }
// 70 | dynamic DynamicClass {
// 70 | dynamic class DynamicClass {
// 71 | d string
// 72 | }
// |
Expand All @@ -149,3 +170,19 @@ test NameAlreadyExists {
// 81 | type_builder {
// 82 | class NonDynamic {
// |
// error: Error validating: Type 'DynamicEnum' is an enum, but the dynamic block is defined as 'dynamic class'
// --> tests/dynamic_types_validation_errors.baml:104
// |
// 103 | type_builder {
// 104 | dynamic class DynamicEnum {
// 105 | C
// 106 | }
// |
// error: Error validating: Type 'DynamicClass' is a class, but the dynamic block is defined as 'dynamic enum'
// --> tests/dynamic_types_validation_errors.baml:107
// |
// 106 | }
// 107 | dynamic enum DynamicClass {
// 108 | c string
// 109 | }
// |
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl std::ops::Index<FieldId> for TypeExpressionBlock {
pub enum SubType {
Enum,
Class,
Dynamic,
Dynamic(Box<Self>),
Other(String),
}

Expand Down
6 changes: 5 additions & 1 deletion engine/baml-lib/schema-ast/src/parser/datamodel.pest
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ schema = {
// Unified Block for Class and Enum
// ######################################
type_expression_block = { identifier ~ identifier ~ named_argument_list? ~ BLOCK_OPEN ~ type_expression_contents ~ BLOCK_CLOSE }

// Dynamic declarations start with the dynamic keyword followed by a normal type expression.
dynamic_type_expression_block = { identifier ~ type_expression_block }

type_expression_contents = {
(type_expression | block_attribute | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)*
}
Expand Down Expand Up @@ -34,7 +38,7 @@ value_expression = { identifier ~ expression? ~ (NEWLINE? ~ field_attri
type_builder_block = {
TYPE_BUILDER_KEYWORD ~ BLOCK_OPEN ~ type_builder_contents ~ BLOCK_CLOSE
}
type_builder_contents = { (type_expression_block | type_alias | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* }
type_builder_contents = { (dynamic_type_expression_block | type_expression_block | type_alias | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* }

// ######################################
ARROW = { SPACER_TEXT ~ "->" ~ SPACER_TEXT }
Expand Down
Loading

0 comments on commit ab78adf

Please sign in to comment.