docs and defs
This commit is contained in:
parent
e7716d038e
commit
2f771c55ac
8 changed files with 290 additions and 81 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -31,9 +31,9 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.16.0"
|
version = "3.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
|
@ -55,9 +55,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.26"
|
version = "4.5.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
|
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -65,9 +65,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.26"
|
version = "4.5.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
|
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
|
@ -75,9 +75,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.24"
|
version = "4.5.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
|
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -410,9 +410,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.43"
|
version = "0.38.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
|
@ -457,9 +457,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.96"
|
version = "2.0.98"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -519,9 +519,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
- [Arithmetic](./lang/arithmetic.md)
|
- [Arithmetic](./lang/arithmetic.md)
|
||||||
- [Bitwise operators](./lang/bitwise.md)
|
- [Bitwise operators](./lang/bitwise.md)
|
||||||
- [Operators reference](./lang/operators.md)
|
|
||||||
- [Variables and scope](./lang/variables.md)
|
- [Variables and scope](./lang/variables.md)
|
||||||
- [Functions](./lang/functions.md)
|
- [Functions](./lang/functions.md)
|
||||||
- [Partial functions and pipes](./lang/partial.md)
|
- [Partial functions and pipes](./lang/partial.md)
|
||||||
|
@ -21,5 +20,8 @@
|
||||||
- [Iterators](./lang/iterators.md)
|
- [Iterators](./lang/iterators.md)
|
||||||
- [Ranges](./lang/ranges.md)
|
- [Ranges](./lang/ranges.md)
|
||||||
- [Exceptions](./lang/exceptions.md)
|
- [Exceptions](./lang/exceptions.md)
|
||||||
|
- [Language reference](./lang/reference.md)
|
||||||
|
- [Grammar](./lang/grammar.md)
|
||||||
|
- [Operators reference](./lang/operators.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
95
docs/src/lang/grammar.md
Normal file
95
docs/src/lang/grammar.md
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
# Grammar
|
||||||
|
|
||||||
|
Some additional restrictions, such as the precedence of operators or the kinds
|
||||||
|
of expressions that are valid to assign to, are not represented here. See the
|
||||||
|
[operators reference](operators.md) for a description of operator precedence.
|
||||||
|
|
||||||
|
```grammar
|
||||||
|
program := block EOF
|
||||||
|
|
||||||
|
# LINESEP: either a semicolon or newline
|
||||||
|
block := LINESEP* (expr LINESEP+)* expr?
|
||||||
|
|
||||||
|
expr := assign
|
||||||
|
| return assign?
|
||||||
|
| break assign?
|
||||||
|
| continue
|
||||||
|
|
||||||
|
assign := pipeline | pipeline assign_op assign
|
||||||
|
|
||||||
|
assign_op := "=" | "++=" | "&=" | "#|=" | "#^=" | "#&=" | "<<=" | ">>=" | "+="
|
||||||
|
| "-=" | "*=" | "/=" | "//=" | "%=" | "^="
|
||||||
|
|
||||||
|
pipeline := lambda | pipeline "|" lambda
|
||||||
|
|
||||||
|
lambda := prec_expr
|
||||||
|
| "\" ident_list "->" lambda
|
||||||
|
| "&" lambda
|
||||||
|
|
||||||
|
# See the operators reference
|
||||||
|
prec_expr := access
|
||||||
|
| prec_expr infix_op prec_expr
|
||||||
|
| prec_expr postfix_op
|
||||||
|
| prefix_op prec_expr
|
||||||
|
|
||||||
|
infix_op := "==" | "!=" | ">" | ">=" | "<" | "<=" | "++" | "&" | ".." | "..="
|
||||||
|
| "#|" | "#^" | "#&" | "<<" | ">>" | "+" | "-" | "*" | "/" | "//"
|
||||||
|
| "%" | "^" | "and" | "or"
|
||||||
|
|
||||||
|
prefix_op := "-" | "!" | "~" | "*.." | "*..="
|
||||||
|
|
||||||
|
postfix_op := "..*"
|
||||||
|
|
||||||
|
access := term access_op*
|
||||||
|
access_op := "(" expr_list ")"
|
||||||
|
| "[" expr "]"
|
||||||
|
| "." IDENT
|
||||||
|
| "->" IDENT "(" expr_list ")"
|
||||||
|
|
||||||
|
var := term
|
||||||
|
| "global" IDENT
|
||||||
|
| "var" IDENT
|
||||||
|
| fn_decl
|
||||||
|
fn_decl := "fn" IDENT? "(" ident_list ")" fn_body
|
||||||
|
fn_body := "do" block "end"
|
||||||
|
| "=" expr
|
||||||
|
|
||||||
|
term := IDENT
|
||||||
|
| "(" expr ")"
|
||||||
|
| "[" list_items "]"
|
||||||
|
| "{" table_items "}"
|
||||||
|
| "$"
|
||||||
|
| "do" block "end"
|
||||||
|
| "if" if_stmt_chain
|
||||||
|
| "while" expr "do" block "end"
|
||||||
|
| "for" IDENT "in" expr "do" block "end"
|
||||||
|
| "try" block catch_block* "end"
|
||||||
|
| INTEGER
|
||||||
|
| FLOAT
|
||||||
|
| IMAGINARY
|
||||||
|
| STRING
|
||||||
|
| SYMBOL
|
||||||
|
| "true"
|
||||||
|
| "false"
|
||||||
|
| "nil"
|
||||||
|
| "*..*"
|
||||||
|
|
||||||
|
if_stmt_chain := expr "then" block if_stmt_end
|
||||||
|
if_stmt_end := "elif" if_stmt_chain
|
||||||
|
| "else" block "end"
|
||||||
|
| "end"
|
||||||
|
|
||||||
|
catch_block := "catch" ("*" | symbol_list) ("in" IDENT)? "do" block
|
||||||
|
symbol_list := (SYMBOL ",")* SYMBOL?
|
||||||
|
|
||||||
|
ident_list := (IDENT ",")* IDENT?
|
||||||
|
|
||||||
|
expr_list := (expr ",")* expr?
|
||||||
|
|
||||||
|
list_items := (list_item ",")* list_item?
|
||||||
|
list_item := ".."? expr
|
||||||
|
|
||||||
|
table_items := (table_item ",")* table_item?
|
||||||
|
table_item := ".." expr
|
||||||
|
| term "=" expr
|
||||||
|
```
|
|
@ -4,7 +4,8 @@ Lists in Talc are written as comma-separated items between square brackets.
|
||||||
Lists may be *heterogeneous* (contain items of different types). Similarly to
|
Lists may be *heterogeneous* (contain items of different types). Similarly to
|
||||||
strings, lists may be concatenated using `++`. Lists can be indexed by writing
|
strings, lists may be concatenated using `++`. Lists can be indexed by writing
|
||||||
the index in square brackets after the list. The first element of the list is
|
the index in square brackets after the list. The first element of the list is
|
||||||
at index zero.
|
at index zero. The `&` operator will add a single element to the end of a list,
|
||||||
|
returning a new list.
|
||||||
|
|
||||||
```talc
|
```talc
|
||||||
>> numbers = [1, 5, 6, 4, 2, 3]
|
>> numbers = [1, 5, 6, 4, 2, 3]
|
||||||
|
@ -13,6 +14,15 @@ at index zero.
|
||||||
4
|
4
|
||||||
>> numbers ++ [8, 9]
|
>> numbers ++ [8, 9]
|
||||||
[1, 5, 6, 4, 2, 3, 8, 9]
|
[1, 5, 6, 4, 2, 3, 8, 9]
|
||||||
|
>> numbers & 7
|
||||||
|
[1, 5, 6, 4, 2, 3, 7]
|
||||||
|
```
|
||||||
|
|
||||||
|
Lists are heterogeneous, so they may contain values of different types.
|
||||||
|
|
||||||
|
```talc
|
||||||
|
>> things = [1, 2.0, "three", 4/1, :five]
|
||||||
|
[1, 2.0, "three", 4/1, :five]
|
||||||
```
|
```
|
||||||
|
|
||||||
Lists are *mutable* and their elements can be assigned to or modified.
|
Lists are *mutable* and their elements can be assigned to or modified.
|
||||||
|
@ -46,3 +56,69 @@ ranges further in their own chapter.
|
||||||
>> squares[*..-3]
|
>> squares[*..-3]
|
||||||
[0, 1, 4, 9, 16]
|
[0, 1, 4, 9, 16]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Interpolation
|
||||||
|
|
||||||
|
Using the `..` operator, a list can be created by combining the elements from
|
||||||
|
multiple different collections
|
||||||
|
|
||||||
|
```talc
|
||||||
|
>> even = [2, 4, 6, 8]
|
||||||
|
[2, 4, 6, 8]
|
||||||
|
>> odd = [1, 3, 5, 7, ..even]
|
||||||
|
[1, 3, 5, 7, 2, 4, 6, 8]
|
||||||
|
>> n = [1, ..[2, 3, 4], 5, ..[6, ..[7, 8]], ..[9]]
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
```
|
||||||
|
|
||||||
|
Any iterator or iterable value can be used
|
||||||
|
|
||||||
|
```talc
|
||||||
|
>> squares = [..(0..10 | map(\x -> x*x))]
|
||||||
|
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Destructuring
|
||||||
|
|
||||||
|
A list can be destructured in an assignment expression as follows:
|
||||||
|
|
||||||
|
```talc
|
||||||
|
>> vals = [6, 2, 8]
|
||||||
|
[6, 2, 8]
|
||||||
|
>> [a, b, c] = vals
|
||||||
|
[6, 2, 8]
|
||||||
|
>> a
|
||||||
|
6
|
||||||
|
>> b
|
||||||
|
2
|
||||||
|
>> c
|
||||||
|
8
|
||||||
|
```
|
||||||
|
|
||||||
|
If the number of elements in the list does not match the number in the
|
||||||
|
destructure, an error is thrown.
|
||||||
|
|
||||||
|
A single interpolation may also be used to collect all remaining values. The
|
||||||
|
interpolation may occur in the beginning, middle, or end of the assignment.
|
||||||
|
|
||||||
|
```talc
|
||||||
|
>> ns = [1, 2, 3, 4, 5]
|
||||||
|
[1, 2, 3, 4, 5]
|
||||||
|
>> [a, b, ..rest] = ns
|
||||||
|
[1, 2, 3, 4, 5]
|
||||||
|
>> a
|
||||||
|
1
|
||||||
|
>> b
|
||||||
|
2
|
||||||
|
>> rest
|
||||||
|
[3, 4, 5]
|
||||||
|
>> [a, ..middle, z] = ns
|
||||||
|
[1, 2, 3, 4, 5]
|
||||||
|
>> a
|
||||||
|
1
|
||||||
|
>> middle
|
||||||
|
[2, 3, 4]
|
||||||
|
>> rest
|
||||||
|
5
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ In increasing order of precedence:
|
||||||
| `..*` | Suffix | Range from |
|
| `..*` | Suffix | Range from |
|
||||||
| `#\|` | Left | Bitwise OR |
|
| `#\|` | Left | Bitwise OR |
|
||||||
| `#^` | Left | Bitwise XOR |
|
| `#^` | Left | Bitwise XOR |
|
||||||
| `#&` | Left | Bitwise AND |
|
| `#&` | Left | Bitwise AND |
|
||||||
| `<< >>` | Left | Shift left and right |
|
| `<< >>` | Left | Shift left and right |
|
||||||
| `+ -` | Left | Add and subtract |
|
| `+ -` | Left | Add and subtract |
|
||||||
| `* / // %` | Left | Multiply, divide, integer divide, modulo |
|
| `* / // %` | Left | Multiply, divide, integer divide, modulo |
|
||||||
|
|
4
docs/src/lang/reference.md
Normal file
4
docs/src/lang/reference.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Language reference
|
||||||
|
|
||||||
|
These pages present a more thorough (and less guided) description of the
|
||||||
|
Talc language.
|
32
docs/theme/highlight.js
vendored
32
docs/theme/highlight.js
vendored
|
@ -105,3 +105,35 @@ hljs.registerLanguage('talc', function() {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
hljs.registerLanguage('grammar', function() {
|
||||||
|
const STR_RE = "'[^']*'|\"[^\"]*\"";
|
||||||
|
const TERMINAL_RE = "\\b[A-Z_]+\\b"
|
||||||
|
const OP_RE = ":=|\\||\\+|\\*|\\?|\\(|\\)"
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "Grammar",
|
||||||
|
contains: [
|
||||||
|
{
|
||||||
|
className: 'string',
|
||||||
|
begin: STR_RE,
|
||||||
|
relevance: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'variable',
|
||||||
|
begin: TERMINAL_RE,
|
||||||
|
relevance: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'literal',
|
||||||
|
begin: OP_RE,
|
||||||
|
relevance: 0
|
||||||
|
},
|
||||||
|
hljs.COMMENT(
|
||||||
|
'#', // begin
|
||||||
|
'\n', // end
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -272,8 +272,15 @@ impl<'s> Parser<'s> {
|
||||||
let ext = self.parse_expr()?;
|
let ext = self.parse_expr()?;
|
||||||
items.push(TableItem::Interpolate(b(ext)));
|
items.push(TableItem::Interpolate(b(ext)));
|
||||||
}
|
}
|
||||||
k if k.expr_first() => {
|
T::True
|
||||||
let key = self.parse_term_not_ident()?;
|
| T::False
|
||||||
|
| T::Nil
|
||||||
|
| T::Dollar
|
||||||
|
| T::Integer
|
||||||
|
| T::String
|
||||||
|
| T::Symbol
|
||||||
|
| T::LParen => {
|
||||||
|
let key = self.parse_term()?;
|
||||||
expect!(self, T::Equal);
|
expect!(self, T::Equal);
|
||||||
let value = self.parse_expr()?;
|
let value = self.parse_expr()?;
|
||||||
items.push(TableItem::Pair(b(key), b(value)));
|
items.push(TableItem::Pair(b(key), b(value)));
|
||||||
|
@ -399,9 +406,10 @@ impl<'s> Parser<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term_not_ident(&mut self) -> Result<Expr> {
|
fn parse_term(&mut self) -> Result<Expr> {
|
||||||
let tok = self.next()?;
|
let tok = self.next()?;
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
|
T::Identifier => Ok(E::Ident(Symbol::get(tok.content)).span(tok.span)),
|
||||||
T::LParen => {
|
T::LParen => {
|
||||||
let e = self.parse_expr()?;
|
let e = self.parse_expr()?;
|
||||||
expect!(self, T::RParen);
|
expect!(self, T::RParen);
|
||||||
|
@ -485,26 +493,46 @@ impl<'s> Parser<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term(&mut self) -> Result<Expr> {
|
fn parse_fn_decl(&mut self) -> Result<Expr> {
|
||||||
let Some(tok) = try_next!(self, T::Identifier | T::Var | T::Global) else {
|
let tok_fn = expect!(self, T::Fn);
|
||||||
return self.parse_term_not_ident()
|
let name = try_next!(self, T::Identifier).map(|t| Symbol::get(t.content));
|
||||||
};
|
expect!(self, T::LParen);
|
||||||
match tok.kind {
|
let args = self.parse_ident_list()?;
|
||||||
T::Identifier => Ok(E::Ident(Symbol::get(tok.content)).span(tok.span)),
|
expect!(self, T::RParen);
|
||||||
|
match expect!(self, T::Do | T::Equal).kind {
|
||||||
|
T::Do => {
|
||||||
|
let content = self.parse_block()?;
|
||||||
|
let end = expect!(self, T::End);
|
||||||
|
Ok(E::FnDef(name, args, b(content)).span(tok_fn.span + end.span))
|
||||||
|
}
|
||||||
|
T::Equal => {
|
||||||
|
let content = self.parse_expr()?;
|
||||||
|
let span = tok_fn.span + content.span;
|
||||||
|
Ok(E::FnDef(name, args, b(content)).span(span))
|
||||||
|
}
|
||||||
|
_ => unreachable!("parse_fn_decl: guaranteed by try_next!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_var(&mut self) -> Result<Expr> {
|
||||||
|
match self.peek()?.kind {
|
||||||
T::Global => {
|
T::Global => {
|
||||||
|
let tok = self.next()?;
|
||||||
let ident = expect!(self, T::Identifier);
|
let ident = expect!(self, T::Identifier);
|
||||||
Ok(E::Global(Symbol::get(ident.content)).span(tok.span + ident.span))
|
Ok(E::Global(Symbol::get(ident.content)).span(tok.span + ident.span))
|
||||||
}
|
}
|
||||||
T::Var => {
|
T::Var => {
|
||||||
|
let tok = self.next()?;
|
||||||
let ident = expect!(self, T::Identifier);
|
let ident = expect!(self, T::Identifier);
|
||||||
Ok(E::Var(Symbol::get(ident.content)).span(tok.span + ident.span))
|
Ok(E::Var(Symbol::get(ident.content)).span(tok.span + ident.span))
|
||||||
}
|
}
|
||||||
_ => unreachable!("guarenteed by try_next"),
|
T::Fn => self.parse_fn_decl(),
|
||||||
|
_ => self.parse_term(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_access(&mut self) -> Result<Expr> {
|
fn parse_access(&mut self) -> Result<Expr> {
|
||||||
let mut lhs = self.parse_term()?;
|
let mut lhs = self.parse_var()?;
|
||||||
loop {
|
loop {
|
||||||
let tok = try_next!(self, T::LParen | T::LBrack | T::Arrow | T::Dot);
|
let tok = try_next!(self, T::LParen | T::LBrack | T::Arrow | T::Dot);
|
||||||
match tok.map(|t| t.kind) {
|
match tok.map(|t| t.kind) {
|
||||||
|
@ -651,7 +679,7 @@ impl<'s> Parser<'s> {
|
||||||
if let Some(op) = self.peek()?.kind.assign_op() {
|
if let Some(op) = self.peek()?.kind.assign_op() {
|
||||||
let lval = LValue::from_expr(lhs)?;
|
let lval = LValue::from_expr(lhs)?;
|
||||||
self.next()?;
|
self.next()?;
|
||||||
let rhs = self.parse_decl()?;
|
let rhs = self.parse_assign()?;
|
||||||
let rhs_span = rhs.span;
|
let rhs_span = rhs.span;
|
||||||
Ok(E::Assign(op, b(lval), b(rhs)).span(lhs_span + rhs_span))
|
Ok(E::Assign(op, b(lval), b(rhs)).span(lhs_span + rhs_span))
|
||||||
} else {
|
} else {
|
||||||
|
@ -659,61 +687,33 @@ impl<'s> Parser<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_decl(&mut self) -> Result<Expr> {
|
|
||||||
let tok_fn = expect!(self, T::Fn);
|
|
||||||
let name = try_next!(self, T::Identifier).map(|t| Symbol::get(t.content));
|
|
||||||
expect!(self, T::LParen);
|
|
||||||
let args = self.parse_ident_list()?;
|
|
||||||
expect!(self, T::RParen);
|
|
||||||
match expect!(self, T::Do | T::Equal).kind {
|
|
||||||
T::Do => {
|
|
||||||
let content = self.parse_block()?;
|
|
||||||
let end = expect!(self, T::End);
|
|
||||||
Ok(E::FnDef(name, args, b(content)).span(tok_fn.span + end.span))
|
|
||||||
}
|
|
||||||
T::Equal => {
|
|
||||||
let content = self.parse_expr()?;
|
|
||||||
let span = tok_fn.span + content.span;
|
|
||||||
Ok(E::FnDef(name, args, b(content)).span(span))
|
|
||||||
}
|
|
||||||
_ => unreachable!("parse_fn_decl: guaranteed by try_next!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_decl(&mut self) -> Result<Expr> {
|
|
||||||
match self.peek()?.kind {
|
|
||||||
T::Fn => self.parse_fn_decl(),
|
|
||||||
_ => self.parse_assign(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr(&mut self) -> Result<Expr> {
|
fn parse_expr(&mut self) -> Result<Expr> {
|
||||||
let tok = try_next!(self, T::Return | T::Break | T::Continue);
|
match self.peek()?.kind {
|
||||||
if let Some(tok) = tok {
|
T::Return => {
|
||||||
match tok.kind {
|
let tok = self.next()?;
|
||||||
T::Return => {
|
if self.peek()?.kind.expr_first() {
|
||||||
if self.peek()?.kind.expr_first() {
|
let expr = self.parse_assign()?;
|
||||||
let expr = self.parse_decl()?;
|
let span = expr.span;
|
||||||
let span = expr.span;
|
Ok(E::Return(Some(b(expr))).span(tok.span + span))
|
||||||
Ok(E::Return(Some(b(expr))).span(tok.span + span))
|
} else {
|
||||||
} else {
|
Ok(E::Return(None).span(tok.span))
|
||||||
Ok(E::Return(None).span(tok.span))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
T::Break => {
|
|
||||||
if self.peek()?.kind.expr_first() {
|
|
||||||
let expr = self.parse_decl()?;
|
|
||||||
let span = expr.span;
|
|
||||||
Ok(E::Break(Some(b(expr))).span(tok.span + span))
|
|
||||||
} else {
|
|
||||||
Ok(E::Break(None).span(tok.span))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T::Continue => Ok(E::Continue.span(tok.span)),
|
|
||||||
_ => unreachable!("parse_expr: guaranteed by try_next!"),
|
|
||||||
}
|
}
|
||||||
} else {
|
T::Break => {
|
||||||
self.parse_decl()
|
let tok = self.next()?;
|
||||||
|
if self.peek()?.kind.expr_first() {
|
||||||
|
let expr = self.parse_assign()?;
|
||||||
|
let span = expr.span;
|
||||||
|
Ok(E::Break(Some(b(expr))).span(tok.span + span))
|
||||||
|
} else {
|
||||||
|
Ok(E::Break(None).span(tok.span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T::Continue => {
|
||||||
|
let tok = self.next()?;
|
||||||
|
Ok(E::Continue.span(tok.span))
|
||||||
|
}
|
||||||
|
_ => self.parse_assign(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue