diff --git a/README.md b/README.md index 0e44d0a..7c7d597 100644 --- a/README.md +++ b/README.md @@ -89,16 +89,25 @@ For floating point numbers, only the most basic decimal format is currently impl 0.464, 3.141, -10.0 ``` -String literals exist in a very basic form. No escape character implemented yet. +String literals are used for include paths, import names and as literal strings in the data section. The following escapes are supported: +| Escape | Result | Comment | +| `\"` | `"` | | +| `\'` | `'` | | +| `\t` | 8 | | +| `\n` | 10 | | +| `\r` | 13 | | +| `\N` | 0x0N | (Can't be followed by a hex digit) | +| `\NN` | 0xNN | | ``` "env.memory", "Hello World!" -this does not work, yet: - "one line\nsecond line", "They said: \"Enough!\"" ``` +Character literals are enclosed in single quotes `'` and support the same escapes as strings. They can contain up to 4 characters and evaluate to the +little-endian representation of these characters. For examples: `'A'` evaluates to `0x41`, `'hi'` evaluates to 0x6968, and `'Crly'` to 0x7a6c7243. + ### Imports WebAssembly imports are specified with a module and a name. In CurlyWas you give them inside a single string literal, seperated by a dot. So a module `env` and name `printString` would be written `"env.printString"`. @@ -295,6 +304,9 @@ So for example this block evaluates to 12: Blocks are used as function bodies and in flow control (`if`, `block`, `loop`), but can also used at any point inside an expression. +Variable re-assignments of the form `name = name expression` can be shortened to `name = expression`, for example `x += 1` to increment `x` by one. This works for all arithmetic, bit and shift operators. +The same is allowed for `name := name expression`, ie. `x +:= 1` increments `x` and returns the new value. + #### Flow control `if condition_expression { if_true_block } [else {if_false_block}]` executes the `if_true_block` if the condition evaluates to a non-zero integer and @@ -304,6 +316,17 @@ the `if_false_block` otherwise (if it exists). It can also be used as an express let a = if 0 { 2 } else { 3 }; // assigns 3 to a ``` +If the `if_false_block` contains exactly one `if` expression or statement you may omit the curly braces, writing `else if` chains like: +``` +if x == 0 { + doOneThing() +} else if x == 1 { + doThatOtherThing() +} else { + keepWaiting() +} +``` + `block name { ... }` opens a named block scope. A branch statement can be used to jump to the end of the block. Currently, `block` can only be used as a statement, returning a value from the block is not yet supported. diff --git a/src/parser.rs b/src/parser.rs index 7a5ac9c..85d9411 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -250,23 +250,23 @@ fn report_errors(errors: Vec>, sources: &Sources) { type LexerError = Simple; fn lexer() -> impl Parser, Error = LexerError> { - let float64 = text::int(10) + let float64 = text::digits(10) .chain::(just('.').chain(text::digits(10))) .then_ignore(just("f64")) .collect::() .map(Token::Float64); - let float = text::int(10) + let float = text::digits(10) .chain::(just('.').chain(text::digits(10))) .collect::() .map(Token::Float); let integer = just::<_, _, LexerError>("0x") - .ignore_then(text::int(16)) + .ignore_then(text::digits(16)) .try_map(|n, span| { u64::from_str_radix(&n, 16).map_err(|err| LexerError::custom(span, err.to_string())) }) - .or(text::int(10).try_map(|n: String, span: Span| { + .or(text::digits(10).try_map(|n: String, span: Span| { n.parse::() .map_err(|err| LexerError::custom(span, err.to_string())) }))