Skip to content

Repository files navigation

Let

linux macos windows

A simple demo language that builds upon FE.

Usage

Usage: let [options] <file>

A simple demo language that builds upon FE.

Arguments:
  <file>                   Input file.

Options:
  -h, --help               Display this help and exit.
  -v, --version            Display version info and exit.
  -d, --dump               Dumps the let program again.
  -e, --eval               Evaluate the let program.

Diagnostics:
      --loc-style <style>  How a diagnostic spells out a source location: `full`
                           (`path:row:col-row:col`), `rowcol` (`path:row:col`),
                           `row` (`path:row`), or msvc (`path(row,col)`).
      --no-snippet         Does not render the offending source line and caret
                           underneath a diagnostic.
      --gutter <width>     Width of a diagnostic's line-number column. [default:
                           `5`]
      --max-rows <num>     Maximum number of rows a diagnostic's snippet renders
                           before eliding its middle; `0` elides nothing.
                           [default: `8`]
      --max-errors <num>   Maximum number of errors to report before dropping
                           the rest; `0` reports all of them. [default: `0`]
      --werror             Treats warnings as errors.

Use "-" as `<file>` to output to stdout.

Diagnostics

Diagnostics are collected in an fe::Error that the lexer and the parser share; main hands it to fe::Error::ack, which throws it once parsing is done. Each message prints the offending source row and underlines the columns the fe::Loc covers, renders its `code` citations in color, and may carry notes pointing at a related location:

test/error/unclosed_paren.let:1:13: error: expected `)`, got `;` while parsing parenthesized expression
    1 | print (1 + 2;
      |             ^
      test/error/unclosed_paren.let:1:7: note: unmatched `(` opened here
    1 | print (1 + 2;
      |       ^

--no-snippet sets fe::Driver::diag.no_snippet, which drops the rows underneath and leaves just the header lines.

Building

If you have a GitHub account setup with SSH, just do this:

git clone --recurse-submodules git@github.com:leissa/let.git

Otherwise, clone via HTTPS:

git clone --recurse-submodules https://github.com/leissa/let.git

Then, build with:

cd let
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j $(nproc)

For a Release build simply use -DCMAKE_BUILD_TYPE=Release.

Invoke the interpreter like so:

./build/bin/let test/test.let -e

Run the test suite via CTest:

ctest --test-dir build

Install with:

cmake --install build --prefix /usr/local

Grammar

p = s ... s EOF         (* program *)
  ;

s = ';'                 (* empty statement *)
  | 'let' ID '=' e ';'  (* let statement *)
  | 'print' e ';'       (* print statement *)
  ;

e = LIT                 (* literal expression *)
  | ID                  (* identifier expression *)
  | '(' e ')'           (* parenthesized expression *)
  | OP1 e               (* unary expression *)
  | e OP2 e             (* binary expression *)
  ;

where

  • LIT = [0-9]+
  • ID = [a-zA-Z][a-zA-Z0-9]*
  • OP1 is one of: +, -
  • OP2 is one of: *, +, -, /

In addition, Let supports

  • /* C-style */ and
  • // C++-sytle comments.

For the sake of the demo, Let is case-insensitive: the lexer folds every identifier and keyword to lower case (so Foo, FOO, and foo denote the same name, and LET/Print are recognized as keywords). This deliberately exercises FE's case-normalizing lexer path (fe::Lexer::accept<Append::Lower>).

Precedence

Ambiguities in the expression productions are resolved according to the operator precedence that is summarized in the following table (strongest binding first):

Operator Description
+e, -e unary plus, unary minus
*, / multiplication, division
+, - addition, subtraction

All binary operators are left associative.

Semantics

All calculations use 64-bit unsigned integer wrap-around arithmetic. Division by zero yields zero. Reading an identifier that was never bound by a let statement is not an error: it evaluates to zero (the name is implicitly bound to 0 on first use).

About

A simple demo language that builds upon FE.

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages