Lumesh syntax handbook

wiki syntax

Lumesh Shell Syntax Manual


Here is the translation of your text into English:


I. Variables and Types

1. Variable Declaration and Assignment

  • Declaring Variables: Use the let keyword, supporting multiple variable declarations. Types are automatically assigned based on the assigned values.

    let x = 10                 # Single variable
    let a, b = 1, "hello" # Multiple variables assigned separately (the number of expressions on the right must match)
    let a, b, c = 1 # Multiple variables assigned the same value
    let a = b = 1 # Multiple variables assigned consecutively
  • Assignment Operators:

    • =: Normal assignment.
    • :=: Delayed assignment (stores the expression as a reference).
    x := 2 + 3  # Delayed evaluation, storing the expression rather than the result
    echo x # Outputs the expression: 2+3
    eval x # Outputs the result: 5
  • Deleting Variables: Use del.

    del x
  • Using Variables: Optional $, directly use echo a x.

Strict mode requires $: echo $x

  • Check Variable Type:
    let a = 10
    type a # Integer
    type a == "Integer" # True

Edge Cases:

  • In strict mode (-s), variables must be initialized; otherwise, an error will be thrown.
  • When declaring multiple variables, the number of expressions on the right must match the number of variables on the left or be a single value; otherwise, a SyntaxError will be thrown.

2. Data Types

Basic Types

Type Example
Integer 42, -3
Float 3.14, -0.5, 10%
String "Hello\n", 'raw'
Boolean True, False
List (Array) [1, "a", True]
Map (Dictionary) {name: "Alice", age: 30}
Range 1..8, 1..10
Time time.parse('2025-5-20')
File Size 4K, 5T
Null None

Complex Types

Type Example
Variable x
Function fn add(x,y){return x+y}
Lambda let add = (x,y) -> x + y
Built-in Library math.floor

Scope Rules

  • Lambda and function definitions create a child environment scope.
  • Child environments inherit variables from the parent environment without modifying the parent scope.

Strings

  • Single quotes denote raw strings.

  • Double quotes support text escaping (e.g., \n), Unicode escaping (e.g., \u{2614}), and ANSI escaping (e.g., \033[34m).

  • Backticks denote string templates, supporting $var variable substitution and ${var} subprocess statement execution capture, as well as ANSI escape characters.

    print "Hello\nworld!\u{2614}"
    Hello # Outputs two lines, \n is escaped to a newline
    world!☔ # Unicode escape, \u{2614} is the umbrella character

    let str2 = 'Hello\nworld!'
    Hello\nworld! # Outputs one line, including the raw form of \n

    let a = [1,2,5]
    print `a is $a, and a[0] is ${a[0]}`

    print "\033[31mRed msg\033[m" # Outputs red colored "Red msg"

    Variable substitution within backticks is more efficient than subprocess statement capture; it is recommended to use the former unless necessary.

  • Edge Cases:

    The \ in single-quoted strings is treated literally (e.g., 'Line\n' outputs Line\n).
    Undefined escape sequences will throw an error, such as:

    echo "Hello\_"

    [PARSE FAILED] syntax error: invalid string escape sequence `\_`
    |
    1 | echo "Hello\_"
    |

File Size Type:

Composed of an integer followed by a unit, supporting the following units:
"B" "K" "M" "G" "T" "P"

Lumesh will automatically recognize the unit and output in a human-readable format, for example:

print 3050M 1038B 3000G

# Output
2.98G 1K 2.93T

File size types can participate in calculations.
For example:

1M > 30K      # Returns True
fs.ls -l | where(size>20K) # Filters files larger than 20K

Date and Time Type

For example: time.parse('2025-5-20')

Date and time types can participate in calculations.
For example:

time.parse('2025-5-20') > time.parse('2025-1-20')  # Returns True

For specific operations, please refer to the built-in time module functions.

Percentages

Written as a percentage, it will be automatically recognized as a float.

print 37% 2% + 3
# Output
0.37 3.02

A percentage sign immediately following a number indicates a percentage, while a space followed by a percentage sign indicates a modulo operation.


2. Operator Rules

1. Operator Categories and Precedence

From highest to lowest precedence (Smaller number means higher priority)

Precedence Operator/Structure Example/Description
1 Parentheses () (a + b) * c
2 Function call, List [] func(arg), [1, 2]
3 Unary operators !, -, __.. !flag, -5
4 Power operator ^ 2 ^ 3
5 Multiplication/division/modulus *, /, %, _*.. a * b % c
6 Addition/subtraction +, -, _+.. a + b - c
7 Comparison ==, !=, > etc a > b
8 Logical AND && cond1 && cond2
9 Logical OR `
10 Ternary operator ? : cond ? t : f
11 Assignment =, := x = 5, let y := 10
12 Pipeline ` `
Redirection << >> >>! date >> /tmp/day.txt

Pipeline and redirection have same precedence, logical operators have higher precedence than pipeline/redirection.

special Operators

  • quals: == means both type and value must be equal.
  • ~= means only value equal.
  • ~~ means regex match.
  • ~: means string contains.
  • & shutdown all output and run in background
  • -& shutdown stdout

look at these examples:

5 == "5"        # False
5 ~= "5" # True
"abc" ~: "a" # True
"abc" ~~ '\d' # False

2. Spacing Rules

Operator Type Spacing Requirement Example
Regular operators Should have spaces on both sides a + b x <= 10
Non-strict mode allows no space for some symbols a+b x<=10 a=5
- and / should have spaces b-3 becomes string, 3-b subtraction
Custom operators Must start with _ and have spaces x _*+ y a _?= b
Postfix operators must start with __ and have spaces x __*+
Prefix operators Space before or start of line, no space after !x -7
Infix operators No space before/after dict.key 1..9
Postfix operators No space before/after func(a) array[i]
May be deprecated in future, not recommended a++ a--

For increment, use a += 1 instead of a++
-- is typically used for shell arguments

Custom Operators:

  • Custom operators start with _, can only contain symbols, not numbers or letters
  • Custom unary operators start with __, e.g., __+, same precedence as unary operators, only for postfix
  • Custom +-level operators start with _+%, e.g., _+%, same precedence as + -
  • Custom *-level operators start with _*, e.g., _*-, same precedence as * /
let __++ = x -> x + 1;
3 __++

Edge Case:

  • x++y invalid, x+++y valid

3. Implicit Type Conversion

Numeric operations automatically convert to higher precision type.
When operating different types, always try to convert to first operand’s type.

# Non-strict mode
3 + "5" # → 8 (converted to integer)
"10" + 2 # → "102" (converted to string)
"10" * 2 # → "1010" (string repetition)
[1,2,3] + 5 # → [1,2,3,5]
[2,3] - 2 # → [3]
{name:wang, age:18} - name # → {age:18}

4. Special Operation Behaviors

5 / 2           # → 2 (integer division)
5.0 / 2 # → 2.5

You can use * for string repetition, similar to Python
echo "+" * 3

You can use * to multiply list elements with second operand
[3,5,7] * 3

Edge Case:

  • Division by zero throws error

5. Pipeline

  • | Smart pipeline: automatically reads from expression result or stdout, passes to next command’s stdin or appends to function arguments
  • |> Pipeline to last argument of right-side function

cmd1 | cmd2 | ...

6. Redirection

  • << Read
  • >> Append output
  • >>! Overwrite output
    1 + 2 >> result.txt

Error redirection: Combine with error handling operators
See Error Handling section for details.

Redirection Type Lume Bash
Standard output append cmd >> out.txt cmd >> out.txt
Standard output overwrite cmd >>! out.txt cmd > out.txt
Error redirected to stdout cmd ?! >> out.log command 2>&1 >> out.log
Separate error output cmd ?? >> out.log cmd 2>> out.log
Combine stdout and stderr cmd ?+ >> out.log cmd >> out.log 2>&1

3. Intervals, Lists, and Maps

1. Intervals

  • Interval Expressions
    Intervals use ..< (left-closed, right-open) or .. (closed interval), with no spaces on either side. Variable expansion is supported.

    0..<10        # does not include 10
    0..10 # includes 10
    a..b

    range support steps::step

    0..6:2     # step is 2: [0,2,4,6]

    Intervals can be used for loops, containment checks, array creation, etc.

    let r = 0..8

    for i in r {...} # More efficient than looping directly over an array
    r ~: 5 # Check if the element is contained
    list.from(r) # Convert to an array

2. Lists (Arrays)

  • Lists are represented with [ ]. The elements inside are ordered.

  • You can also create lists directly from intervals using ... or ...<.

    0...5               # Outputs [0, 1, 2, 3, 4]
    # Equivalent to
    list.from(0..5)

Two dots .. ..< create intervals, while three dots ... ...< create arrays.

  • Indexing is represented with . or [i].

    let arr = [10, "a", True]
  • Indexing and Slicing

    # Basic Indexing

    arr.1
    arr[0] # → 10

    # Slicing Operations
    arr[1:3] # → ["a", True] (left-closed, right-open)
    arr[::2] # → [10, True] (step of 2)
    arr[-1:] # → True (slicing supports negative indexing)
  • Complex Nesting

    # Complex Nesting
    [1, 24, 5, [5, 6, 8]][3][1] # Displays 6
    # Modify Element
    # arr[2] = 3.14 # → [10, "a", 3.14]
  • Advanced Operations
    Refer to the list module.

Edge Cases:

  • Accessing an array index that is out of bounds will trigger an out of bounds error.
  • Array slicing supports negative numbers, indicating indices counted from the end.
  • Indexing a non-indexable object will trigger the following error:
    [ERROR] type error: expected indexable type (list/dict/string), found symbol

3. Maps (Dictionaries)

  • Maps are represented with {}.

    let mydict = {name: "Alice", age: 30}
  • Dictionary Indexing

    # Basic Access

    mydict["name"] # → "Alice"
    mydict.name # → "Alice" (shorthand)

    # Dynamic Key Support
    let key = "ag" + "e"
    dict[key] # → 30

    # Nested Access
    let data = {user: mydict}
    data.user.age # → 30
  • Advanced Operations
    Refer to the map module.

Edge Cases:

Scenario Behavior
Accessing a non-existent array index Triggers [ERROR] key x not found in map error
Indexing a non-dictionary object Triggers [ERROR] not valid index option error
Indexing an undefined symbol Returns a string, as operating on filenames is a common operation in shell
Indexing an undefined symbol Returns a string, as operating on filenames is a common operation in shell

4. Statements

  1. Statement Blocks
    Use {}. Typically for flow control.

  2. Subcommand Groups
    Parentheses execute as subcommand, doesn’t create new process or isolate variable scope.
    echo (len [5,6])

  3. Statement Separation
    Use ; or Enter to separate:

    • Line Break: ; or newline
    • Line Continuation: Use \ + newline for multi-line:
    let long_expr = 3 \
    + 5 # Equivalent to "3 + 5"

    let long_str = "Hello
    World" # Equivalent to "Hello\n World"

    Note: No need for line continuation inside quotes.

  4. Comment
    comment begin with #


5. Control Structures

  1. Conditional Statements

    • If Statement
      Supports nesting:
      if cond1 { ... } else if cond2 { ... } else { ... }

    No then keyword, code blocks use {}:

    if True {1} else {if False {2} else {3}}

    if x > 10 {
    print("Large")
    } else if x == 10 {
    print("Equal")
    } else {
    print("Small")
    }
    • Match Statement
      Replaces bash switch:
    let x = "a"
    match x {
    "b" => echo "is letter",
    _ => echo "is others"
    }
  2. Loops

    • For Loop:
      for i in 0..5 {    # Outputs 0,1,2,3,4
      print(i)
      }

      for i in [1,5,8] { print i }
    • While Loop:
      let count = 0
      while count < 3 {
      print(count)
      count = count + 1
      }
  3. Statement Expressions

    • Control statements can also act as expressions:
    let a = if b>0 {5} else {-5}
    • Ternary Expression
    a = c>0 ? t : f

    Supports nesting.

    • Range Expression
      Use .. with no space around, supports variable expansion:
    0..10
    # Equivalent to
    [0,1,2,3,4,5,6,7,8,9]
    # Equivalent to
    let a=0
    let b=10
    a..b

6. Functions

  1. Function Definition

    • Use fn keyword, supports default parameters and rest parameter collection:
    fn add(a,b,c=10,*d) {
    return a + b + c + len(c)
    }

    # Equivalent to:
    fn add(a,b,c=10,*d) {
    a + b + c + len(c)
    }

    echo add(2, 3) # Output: 5
    echo add(2,3,4, 5) # Output: 10
  2. Lambda Expressions

    • Defined with ->.
      Differences from normal functions:
      • No default parameters or return statement
      • Supports partial application, returns subsequent lambda
        Both inherit current environment variables and run in isolated environment.
    let add = (x,y) -> x + y
  3. Function Calls
    Differentiating function calls from command execution:

    # Test case 6: Function-command name conflict
    fn ls() { echo "My ls" }
    ls -l # Executes system command ls
    ls() # Calls function
    ls! -l # Using ! suffix, function call syntax sugar

    Function Call

    # Custom function call
    add(3,5)
    # Or
    add! 3 5 # Note: ! suffix required to differentiate from command

    Command Call

    ls -l

    Built-in Commands

    All three forms supported:

    fmt.red(msg)
    fmt.red! msg
    fmt.red msg

Edge Cases:

  • New function definitions override existing ones with same name
  • Parameter count mismatch throws error:
    [ERROR] arguments mismatch for function add: expected 3, found 1

7. Running System Commands

The main task of a shell is to run system commands, and secondly, to improve efficiency through powerful programming capabilities.

Command Execution

In lumesh, you can conveniently run programs just like in other shells, such as:

ls
ls -l

If multiple commands are issued, subsequent commands will not execute if the preceding command fails; unless errors are ignored:

ls '/0' ; ls -l         # The latter will not execute
ls '/0' ?. ; ls -l # The latter will execute

Wildcard Expansion

In lumesh, ~ directory expansion and * expansion are also supported:

ls ~/**/*.md

However, {} expansion as in bash is not supported.

Background Execution and Output Control

  • Similar to bash, use the & symbol to run programs in the background.
  • Output control symbol &: We adopt a more concise way to suppress output.
thunar &         # run in background, and shut down stdout and stderr
ls &- # shut down stdout
ls /o &? # shut down stderr
ls /o '/' &+ # shut down stdout and stderr

ls /o '/' &? | bat # shut down stderr and pipe stdout to the next command.

Here is a comparison of syntax with bash:

Task bash lumesh
Background Run cmd & cmd &
Suppress Stdout cmd 1> /dev/null cmd &-
Suppress Stderr cmd 2> /dev/null cmd &?
Suppress All Output cmd 2>&1 /dev/null cmd &.

Piping

lumesh uses the same pipe symbol as bash, but it is more powerful:

  • | Smart pipe, the left side can automatically read from the computation result or standard output, and if the right side is a third-party command, it will receive data as standard input; if it is a function, it will be passed as the last argument.
  • |> Pipe to the last argument of the right-side function.

cmd1 | cmd2 | ...

Redirection

  • << Read
  • >> Append output
  • >>! Overwrite output
    1 + 2 >> result.txt

Error redirection: combined with error handling symbols.
For specific usage, please refer to the error handling section.

Redirection Type Lume Bash
Standard Output, Append cmd >> out.txt cmd >> out.txt
Standard Output, Overwrite cmd >>! out.txt cmd > out.txt
Error Redirecting Standard Output cmd ?! >> out.log command 2>&1 >> out.log
Separate Error Output cmd ?? >> out.log cmd 2>> out.log
Merge Standard and Error Output cmd ?+ >> out.log cmd >> out.log 2>&1

8. Error Handling

  • Error Handling: ?:
    Statement followed by ?: expr, where expr can be a lambda accepting an Error object (Map type with code, msg, and expr properties):
6 / 0 ?.    # Ignore error
6 / 0 ?+ # Print error to stdout
6 / 0 ?? # Print error to stderr
6 / 0 ?! # Use error message as result

let e = x -> echo x.code
6 /0 ?: e # Handle error with function/lambda

Tips

  • Use error handling to provide default values:
let e = x -> 0
let result = 6 /0 ?: e
echo result # Output default: 0

# Equivalent
let result = 6 /0 ?: 0
echo result # Output default: 0
  • Use error handling in function define:
let e = x -> {print x.code}

fn div(a,b){
a / b
} ?: e

div(3,0) # the defined error handling will be executed here.

9. Execution Modes

  1. REPL Interactive Mode

    • Interactive user interface with syntax highlighting
      Auto Hint:
    • type anything will trigger auto hint, mathes executable cmds, builtin functions, syntax, alias,history.
    • type module_name+dot+space: fs. to see all functions in the module.

    Auto Complete

    • Tab: Auto-completion:
      • First word: matches executable commands,builtin functions,syntax,alias.
      • Path-related: triggers path completion
      • More than 2 words: triggers AI completion
        AI requires configuration first default config is for ollama, just run it and AI should work.
        Keys
    • Right or Ctrl+J: Accept completion suggestions
    • Alt+J : Accept one world suggestion
    • Ctrl+D: EOF
    • Ctrl+C: Cancel operation

    see hotkeys to find out more.

    History: Saved in config directory

    • UP/DOWN or Ctrl+N/P: Navigate history
  2. Script Parsing Mode
    Run script: lume ./my.lm

  3. Login Shell Mode
    Configure environment variables in config file similar to .bashrc

  4. Strict Mode

    • Variables must be declared with $ prefix
    • Variables must be declared before use
    • No type conversion allowed
    • Non-strict mode allows direct variable access without $

10. Parameters and Environment Variables

  1. Command-line Arguments:

    • Accessed through argv list:
    # Run lumesh script.lm Alice tom
    echo argv # Output: "[Alice, tom]"
    echo argv@0 # Output: "Alice"
  2. Environment Variables

    PATH             # System environment variable
    HOME # System environment variable

    env # List all environment variables
    IS_LOGIN # Is login shell?
    IS_INTERACTIVE # Is interactive mode?
    IS_STRICT # Is strict mode?

11. Configuration File

  • supported settings
  1. Special settings for different mode.
  2. AI config。
  3. key-bindings。
  4. abbreviations。
  5. alias。
  6. history file path。

see default config for details.

  • config
    if not specified in cmd, lume will read config file from default path with entry lumesh/config.lm.
    this is:
Platform Value Example
Linux $XDG_CONFIG_HOME or $HOME/.config /home/alice/.config
macOS $HOME/Library/Application Support /Users/Alice/Library/Application Support
Windows {FOLDERID_RoamingAppData} C:\Users\Alice\AppData\Roaming

to see yours, just type fs.dirs()

  • history record
    if not specified in config file, history record was located in default cache dir with name lume_history.
    this is :
Platform Value Example
Linux $XDG_CACHE_HOME or $HOME/.cache /home/alice/.cache
macOS $HOME/Library/Caches /Users/Alice/Library/Caches
Windows {FOLDERID_LocalAppData} C:\Users\Alice\AppData\Local

to see yours, just type fs.dirs()

12. Built-in Functions

Use help command to list all.

See Built-in Lib Library for details.

By following this manual, users can master Lumesh’s core syntax and edge cases. Practice in REPL is recommended for better understanding.