Skip to content

Commit

Permalink
Validate type aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniosarosi committed Nov 14, 2024
1 parent ade4200 commit ad299e6
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ typpe Two = float
// 8 | // Unexpected keyword.
// 9 | typpe Two = float
// |
// error: The type_alias "One" cannot be defined because a class with that name already exists.
// --> class/invalid_type_aliases.baml:6
// |
// 5 | // Already existing name.
// 6 | type One = int
// |
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,33 @@ type List = string[]

type Graph = map<string, string[]>

type Combination = Primitive | List | Graph
type Combination = Primitive | List | Graph

function AliasPrimitive(p: Primitive) -> Primitive {
client "openai/gpt-4o"
prompt r#"
Return the given value back: {{ p }}
"#
}

function MapAlias(m: Graph) -> Graph {
client "openai/gpt-4o"
prompt r#"
Return the given Graph back:

{{ m }}

{{ ctx.output_format }}
"#
}

function NestedAlias(c: Combination) -> Combination {
client "openai/gpt-4o"
prompt r#"
Return the given value back:

{{ c }}

{{ ctx.output_format }}
"#
}
21 changes: 16 additions & 5 deletions engine/baml-lib/parser-database/src/names/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ pub(super) struct Names {
/// - Generators
/// - Model fields for each model
pub(super) fn resolve_names(ctx: &mut Context<'_>) {
let mut tmp_names: HashSet<&str> = HashSet::default(); // throwaway container for duplicate checking
let mut enum_value_names: HashSet<&str> = HashSet::default(); // throwaway container for duplicate checking
let mut names = Names::default();

for (top_id, top) in ctx.ast.iter_tops() {
assert_is_not_a_reserved_scalar_type(top.identifier(), ctx);

let namespace = match (top_id, top) {
(_, ast::Top::Enum(ast_enum)) => {
tmp_names.clear();
enum_value_names.clear();
validate_enum_name(ast_enum, ctx.diagnostics);
validate_attribute_identifiers(ast_enum, ctx);

Expand All @@ -50,7 +50,7 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) {

validate_attribute_identifiers(value, ctx);

if !tmp_names.insert(value.name()) {
if !enum_value_names.insert(value.name()) {
ctx.push_error(DatamodelError::new_duplicate_enum_value_error(
ast_enum.name.name(),
value.name(),
Expand Down Expand Up @@ -90,6 +90,17 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) {
(_, ast::Top::Class(_)) => {
unreachable!("Encountered impossible class declaration during parsing")
}

(ast::TopId::TypeAlias(_), ast::Top::TypeAlias(type_alias)) => {
validate_type_alias_name(type_alias, ctx.diagnostics);

Some(either::Left(&mut names.tops))
}

(_, ast::Top::TypeAlias(_)) => {
unreachable!("Encountered impossible type alias declaration during parsing")
}

(ast::TopId::TemplateString(_), ast::Top::TemplateString(template_string)) => {
validate_template_string_name(template_string, ctx.diagnostics);
validate_attribute_identifiers(template_string, ctx);
Expand Down Expand Up @@ -136,13 +147,13 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) {

(_, ast::Top::Generator(generator)) => {
validate_generator_name(generator, ctx.diagnostics);
check_for_duplicate_properties(top, generator.fields(), &mut tmp_names, ctx);
check_for_duplicate_properties(top, generator.fields(), &mut enum_value_names, ctx);
Some(either::Left(&mut names.generators))
}

(ast::TopId::TestCase(testcase_id), ast::Top::TestCase(testcase)) => {
validate_test(testcase, ctx.diagnostics);
check_for_duplicate_properties(top, testcase.fields(), &mut tmp_names, ctx);
check_for_duplicate_properties(top, testcase.fields(), &mut enum_value_names, ctx);

// TODO: I think we should do this later after all parsing, as duplication
// would work best as a validation error with walkers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub(crate) fn validate_class_name(
validate_name("class", ast_class.identifier(), diagnostics, true);
}

pub(crate) fn validate_type_alias_name(ast_class: &ast::Assignment, diagnostics: &mut Diagnostics) {
validate_name("type alias", ast_class.identifier(), diagnostics, true);
}

pub(crate) fn validate_class_field_name<T>(
ast_class_field: &ast::Field<T>,
diagnostics: &mut Diagnostics,
Expand Down
13 changes: 7 additions & 6 deletions engine/baml-lib/schema-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ pub use value_expression_block::{BlockArg, BlockArgs, ValueExprBlock, ValueExprB

/// AST representation of a prisma schema.
///
/// This module is used internally to represent an AST. The AST's nodes can be used
/// during validation of a schema, especially when implementing custom attributes.
/// This module is used internally to represent an AST. The AST's nodes can be
/// used during validation of a schema, especially when implementing custom
/// attributes.
///
/// The AST is not validated, also fields and attributes are not resolved. Every node is
/// annotated with its location in the text representation.
/// Basically, the AST is an object oriented representation of the datamodel's text.
/// Schema = Datamodel + Generators + Datasources
/// The AST is not validated, also fields and attributes are not resolved. Every
/// node is annotated with its location in the text representation.
/// Basically, the AST is an object oriented representation of the datamodel's
/// text. Schema = Datamodel + Generators + Datasources
#[derive(Debug)]
pub struct SchemaAst {
/// All models, enums, composite types, datasources, generators and type aliases.
Expand Down
4 changes: 2 additions & 2 deletions engine/baml-lib/schema-ast/src/ast/assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ impl WithSpan for Assignment {
}
}

// TODO: Right now the left side is always an identifier, but if ends up being
// an expression we'll have to refactor this somehow.
// TODO: Right now the left side is always an identifier, but if it ends up
// being an expression we'll have to refactor this somehow.
impl WithIdentifier for Assignment {
fn identifier(&self) -> &Identifier {
&self.identifier
Expand Down
2 changes: 1 addition & 1 deletion engine/baml-lib/schema-ast/src/ast/top.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Top {
Top::Enum(_) => "enum",
Top::Class(_) => "class",
Top::Function(_) => "function",
Top::TypeAlias(_) => "type",
Top::TypeAlias(_) => "type_alias",
Top::Client(_) => "client<llm>",
Top::TemplateString(_) => "template_string",
Top::Generator(_) => "generator",
Expand Down

0 comments on commit ad299e6

Please sign in to comment.