Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 98 additions & 3 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ thiserror = "2.0.9"
clap = { version = "4.5.23", features = ["cargo", "derive"] }
rustyline = "17.0"
eyre = "0.6.12"
dirs = { version = "2.0", package = "dirs-next" }

[dev-dependencies]
bigdecimal = "0.4"
Expand All @@ -27,5 +28,9 @@ futures = "0.3.31"
name = "features"
harness = false

[[test]]
name = "repl"
harness = false

[workspace.lints.clippy]
unwrap_used = "deny"
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ This folder contains initial documentation for the `flt` language as it exists i
## Contents

- [`quickstart.md`](quickstart.md) - Running `flt` and trying expressions in the REPL.
- [`syntax.md`](syntax.md) - Core expression forms, literals, comments, and identifiers.
- [`syntax.md`](syntax.md) - Core expression forms, literals, comments, identifiers, reserved keywords, and statements.
- [`operators.md`](operators.md) - Unary/binary operators and precedence.
- [`functions-and-pipe.md`](functions-and-pipe.md) - Function call syntax and pipe chaining.
- [`functions-and-pipe.md`](functions-and-pipe.md) - Function call syntax (including keyword arguments) and pipe chaining.
- [`runtime-and-limitations.md`](runtime-and-limitations.md) - Evaluation behavior, errors, and current limitations.

## Scope
Expand Down
14 changes: 13 additions & 1 deletion docs/functions-and-pipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ bar(1)
add(1, 2)
```

### Keyword arguments

In the parenthesized form, arguments may include trailing **keyword arguments**: key-value pairs with the form `key: value`. All positional arguments must come first; after the first keyword argument, no further positional arguments are allowed.

```flt
foo(1, bar: true)
baz(a: 1, b: 2)
qux(1, 2, option: "value")
```

Keys follow the same rules as map keys (bare identifier or quoted string). The parser collects keyword arguments into a single map and passes them as the final argument to the call.

### Whitespace form

In this form, at least one argument is required.
Expand All @@ -34,5 +46,5 @@ The parser treats this as a left-associative binary operator chain.

## Current Semantics Note

- Parsing for function calls and pipe expressions is implemented.
- Parsing for function calls (including keyword arguments) and pipe expressions is implemented.
- Runtime evaluation for function calls and pipe is not implemented yet in `flt-cli`.
7 changes: 7 additions & 0 deletions docs/operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
| `|` | bitwise or (parsed) | `a | b` |
| `^` | bitwise xor (parsed) | `a ^ b` |
| `|>` | pipe | `x |> f` |
| `==` | equality | `x == 1` |
| `!=` | inequality | `x != 0` |
| `<` | less than | `a < b` |
| `>` | greater than | `a > b` |
| `<=` | less than or equal | `a <= b` |
| `>=` | greater than or equal | `a >= b` |

## Precedence (Low to High)

Expand All @@ -36,6 +42,7 @@
7. `&`
8. `+`, `-`, `<>`
9. `*`, `/`
10. `==`, `!=`, `<`, `>`, `<=`, `>=`

All binary levels are left-associative.

Expand Down
4 changes: 3 additions & 1 deletion docs/runtime-and-limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ Common errors include:

These constructs parse successfully but are not fully supported by the current evaluator:

- Function calls
- Function calls (including calls with keyword arguments, e.g. `foo(1, bar: true)`)
- Pipe expressions (`|>`)
- Bitwise operators (`&`, `|`, `^`)
- Let statements (`let x = expr`) — the REPL accepts expressions only; statement parsing is available in the library for other entry points
- Standalone keyword expressions (e.g. `if`, `return`, `fn`) — they parse as expressions but have no evaluation behavior yet

## Practical Guidance

Expand Down
32 changes: 30 additions & 2 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,36 @@ This page covers the core surface syntax supported by the parser.
- Identifiers
- Unary expressions
- Binary expressions
- Function calls
- Function calls (including [keyword arguments](./functions-and-pipe.md#keyword-arguments))
- Parenthesized expressions
- Reserved keywords as expressions (e.g. `if`, `return`)

## Statements

The parser supports **let bindings**:

```flt
let x = 1
let name = "flt"
let foo = 2 + 3
```

- A statement may be followed by an optional `;`.
- If a statement ends on a newline, the semicolon is not required.
- Two statements on the same line require `;` after the first: `let x = 1; let y = 2`.

The REPL currently accepts expressions only; statement parsing is available for use in other entry points (e.g. batch or file evaluation).

## Reserved Keywords

The following words are reserved and recognized with word boundaries (e.g. `if` is a keyword, but `iffy` is an identifier):

| Keyword | Keyword | Keyword |
| --- | --- | --- |
| `if` | `else` | `return` |
| `and` | `or` | `not` |
| `for` | `in` | `let` |
| `while` | `do` | `fn` |

## Identifiers

Expand All @@ -21,7 +49,7 @@ Identifiers are parsed as one or more of:
- `_`
- `-`

In practice, expression parsing prefers literals before identifiers. For example, `true` and `false` parse as booleans, and a leading numeric form is parsed as a number first.
In practice, expression parsing prefers literals before identifiers. For example, `true` and `false` parse as booleans, and a leading numeric form is parsed as a number first. Reserved keywords (e.g. `if`, `let`) are parsed as keywords when they appear as whole words; identifiers like `iffy` or `input` do not match the `if` or `in` keyword.

Examples:

Expand Down
32 changes: 31 additions & 1 deletion features/ast/binary.feature
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Feature: Binary expressions

Binary operators combine two expressions. Precedence (lowest to highest):
`|>`, `||`, `&&`, `^^`, `|`, `^`, `&`, `+`/`-`/`<>`, `*`, `/`.
`|>`, `||`, `&&`, `^^`, `|`, `^`, `&`, `+`/`-`/`<>`, `*`, `/`, `==`, `!=`, `<`, `>`, `<=`, `>=`.

Scenario: Addition
Given the input "1 + 2"
Expand Down Expand Up @@ -57,3 +57,33 @@ Feature: Binary expressions
Given the input "x |> f"
When I parse the input
Then the output should be 'BinaryExpr(Ident("x"), Pipe, Ident("f"))'

Scenario: Equality
Given the input "x == 1"
When I parse the input
Then the output should be 'BinaryExpr(Ident("x"), Eq, Literal(Number(Numeric { value: BigDecimal(sign=Plus, scale=0, digits=[1]) })))'

Scenario: Inequality
Given the input "x != 0"
When I parse the input
Then the output should be 'BinaryExpr(Ident("x"), Ne, Literal(Number(Numeric { value: BigDecimal(sign=NoSign, scale=0, digits=[]) })))'

Scenario: Less than
Given the input "a < b"
When I parse the input
Then the output should be 'BinaryExpr(Ident("a"), Lt, Ident("b"))'

Scenario: Greater than
Given the input "a > b"
When I parse the input
Then the output should be 'BinaryExpr(Ident("a"), Gt, Ident("b"))'

Scenario: Less than or equal
Given the input "a <= b"
When I parse the input
Then the output should be 'BinaryExpr(Ident("a"), Lte, Ident("b"))'

Scenario: Greater than or equal
Given the input "a >= b"
When I parse the input
Then the output should be 'BinaryExpr(Ident("a"), Gte, Ident("b"))'
3 changes: 2 additions & 1 deletion features/repl/basic.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Feature: flt repl
"""
1 + 1
"""
Then the output should contain "2"
Then the command should succeed
And the output should contain "2"
11 changes: 11 additions & 0 deletions features/syntax/assignment.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Feature: Assignment

Scenario: Assigning a value to a variable
Given the input "let x = 1;"
When I parse the input
Then the output should be a `Statement::Let(Identifier("x"), Expr::Literal(Literal::Number(1)))`

Scenario: Assigning a value without a let keyword
Given the input "x = 1;"
When I parse the input
Then the output should be a `Statement::Let(Identifier("x"), Expr::Literal(Literal::Number(1)))`
Loading
Loading