Skip to content

Commit

Permalink
feat: implement maps in BAML (#797)
Browse files Browse the repository at this point in the history
Add support for maps in the BAML language. We currently only support
maps with string keys.

Here's the work item list that we verified (fortunately, most of these
were already pre-implemented):

- integ-tests (python, ts, ruby)
- parser for the compiler
    - grammar
    - schema-ast
- parser for codemirror
    - lezer
- vscode: textmate grammar
- diagnostics
    - not sure what this means concretely
- in-Rust implementation, i.e. BamlValue
- value syntax
    - ie how you define a map in a test
- input layer (lang-native object → BamlValue)
- ctx.output_format
- output layer (BamlValue → lang-native object)
- codegen (python, ts, ruby)

We also added:

- a new entry point for `validate_type_allowed` where we apply
refinements to the lexed types
- textmate grammar snapshot testing using vscode-tmgrammar-snap

Fixes #787
  • Loading branch information
sxlijin authored Jul 19, 2024
1 parent e8c1a61 commit 97d7e62
Show file tree
Hide file tree
Showing 74 changed files with 2,354 additions and 288 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PATH_add tools/
PATH_add "$(brew --prefix llvm)/bin"

# Use mise for tool versioning, e.g. Ruby
eval "$(mise activate bash)" || echo "Please run 'brew install mise'"
57 changes: 39 additions & 18 deletions docs/docs/snippets/supported-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ function DescribeImage(myImg: image) -> string {
"#
}
```
You cannot name as variable "image" at the moment as it is a reserved keyword.

You cannot name a variable `image` at the moment as it is a reserved keyword.

Calling a function with an image type:

<CodeBlocks>
```python Python
from baml_py import Image
Expand Down Expand Up @@ -148,6 +150,7 @@ enum Name {
Value2 @description("My optional description annotation")
}
```

### class

**See also:** [Class](/docs/syntax/class)
Expand All @@ -157,6 +160,7 @@ Classes are for user-defined complex data structures.
Use when you need an LLM to call another function (e.g. OpenAI's function calling), you can model the function's parameters as a class. You can also get models to return complex structured data by using a class.

**Example:**

Note that properties have no `:`
```baml
class Car {
Expand All @@ -166,10 +170,12 @@ class Car {
```

### Optional (?)

A type that represents a value that might or might not be present.

Useful when a variable might not have a value and you want to explicitly handle its absence.
**Syntax:** `<type>?`

**Syntax:** `Type?`

**Example:** `int?` or `(MyClass | int)?`

Expand All @@ -178,30 +184,45 @@ Useful when a variable might not have a value and you want to explicitly handle
A type that can hold one of several specified types.

This can be helpful with **function calling**, where you want to return different types of data depending on which function should be called.
- **Syntax:** `<type>|<type>`
- **Example:** `int | string` or `(int | string) | MyClass` or `string | MyClass | int[]`
<Warning>
Order is important. `int | string` is not the same as `string | int`.
<br />
For example, if you have a `"1"` string, it will be parsed as an `int` if
you use `int | string`, but as a `string` if you use `string | int`.
</Warning>

**Syntax:** `Type1 | Type2`

**Example:** `int | string` or `(int | string) | MyClass` or `string | MyClass | int[]`

<Warning>
Order is important. `int | string` is not the same as `string | int`.

For example, if you have a `"1"` string, it will be parsed as an `int` if
you use `int | string`, but as a `string` if you use `string | int`.
</Warning>

### List/Array ([])

A collection of elements of the same type.
- **Syntax:** `<type>[]`
- **Example:** `string[]` or `(int | string)[]` or `int[][]`

**Syntax:** `Type[]`

**Example:** `string[]` or `(int | string)[]` or `int[][]`

<Tip>
<ul>
<li>Array types can be nested to create multi-dimensional arrays</li>
<li>An array type cannot be optional</li>
</ul>
* Array types can be nested to create multi-dimensional arrays
* An array type cannot be optional
</Tip>

### ❌ Dictionary
### Map

- Not yet supported. Use a `class` instead.
A mapping of strings to elements of another type.

**Syntax**: `map<string, ValueType>`

**Example**: `map<string, string>`

{/* <Info>
For TS users: `map<string, ValueType>` will generate a
`Record<string, ValueType>` type annotation, but using any other type for the
key will generate a `Map`, e.g. `map<int, string>` in BAML will generate a
`Map<number, string>` type annotation in TypeScript.
</Info> */}

### ❌ Set

Expand Down
5 changes: 5 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"devDependencies": {
"fern-api": "^0.31.24"
}
}
1 change: 1 addition & 0 deletions engine/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl IRHelper for IntermediateRepr {
for (param_name, param_type) in function_params {
scope.push(param_name.to_string());
if let Some(param_value) = params.get(param_name.as_str()) {
if let Some(baml_arg) = to_baml_arg::validate_arg(
if let Ok(baml_arg) = to_baml_arg::validate_arg(
self,
param_type,
param_value,
Expand Down
Loading

0 comments on commit 97d7e62

Please sign in to comment.