mers/docs/syntax_cheat_sheet.md
2023-05-25 00:25:50 +02:00

5.8 KiB

mers syntax cheat sheet

Types

  • bool
  • int
  • float
  • string
  • tuple: [<type1> <type2> <type3> <...>]
  • list: [<type> ...]
  • function: fn(<input-output-map>) (might change? depends on implementation of generics)
  • thread: thread(<return_type>)
  • reference: &<type>
  • enum: EnumName(<type>)
  • one of multiple types: <type1>/<type2>/<type3>

Values

  • bool
    • true or false
  • int
    • decimal: 2, +2, -5, 0, ...
  • float
    • decimal: 1.5, 0.5, -5.2, 2.0, ... (this is recommended for compatability and clarity)
    • whole numbers: 1.0, 1., ... (may break with future updates)
    • numbers from 0 to 1: .5 would be ambiguous following tuples, so is not supported.
  • string
    • "my string" (double quotes)
    • "it's called \"<insert name>\"" (escape inner double quotes with backslash)
    • all escape sequences
      • \" double quote character
      • \\ backslash character
      • \n newline
      • \r carriage return
      • \t tab
      • \0 null
  • tuple
    • [<val1> <val2> <val3> <...>]
  • list
    • [<val1> <val2> <val3> <...> ...] (like tuple, but ...] instead of ])
  • function
    • (<arg1> <arg2> <arg3> <...>) <statement> where <argn> is <namen> <typen>.
  • thread
    • returned by the builtin function thread()
  • reference
    • to a variable: &<varname>
    • to something else: usually using get() or its equivalent on a reference to a container instead of the container itself: &list.get() instead of list.get()
  • enum
    • <EnumName>: <statement>

Variables

  • declaration and initialization
    • <var_name> := <statement>
    • can shadow previous variables with the same name: x := 5 { x := 10 debug(x) } debug(x) prints 10 and then 5.
  • assignment
    • &<var_name> = <statement>
      • modifies the value: x := 5 { &x = 10 debug(x) } debug(x) prints 10 and then 10.
    • <statement_left> = <statement_right>
      • assigns the value returned by <statement_right> to the value behind the reference returned by <statement_left>.
      • if <statement_right> returns <type>, <statement_left> has to return &<type>.
      • this is why &<var_name> = <statement> is the way it is.
    • ***<statement_left> = <statement_right>
      • same as before, but performs dereferences: &&&&int becomes &int (minus 3 references because 3 *s), so a value of type int can be assigned to it.

Statements

  • value
    • 10, true, "text", "[]", etc
  • tuple
    • [<statement1> <statement2> <...>]
  • list
    • [<statement1> <statement2> <...> ...]
  • variable
    • <var_name> (if the name of the variable isn't a value or some other kind of statement)
  • function call
    • <fn_name>(<arg1> <arg2> <...>)
    • <fn_name>(<arg1>, <arg2>, <...>)
    • <arg1>.<fn_name>(<arg2>, <...>)
  • function definition
    • fn <fn_name>(<arg1> <arg2> <...>) <statement> where <argn> is <namen> <typen>
  • block
    • { <statement1> <statement2> <...> }
  • if
    • if <condition> <statement> (if true println("test"))
    • if <condition> <statement> else <statement> (if false println("test") else println("value was false"))
  • loop
    • loop <statement>
    • if the statement returns a value that matches, the loop will end and return the matched value
    • the loop's return type is the match of the return type of the statement
  • for loop
    • for <var_name> <iterator> <statement>
    • in each iteration, the variable will be initialized with a value from the iterator.
    • iterators can be lists, tuples, or functions.
    • for function iterators, as long as the returned value matches, the matched value will be used. if the value doesn't match, the loop ends.
    • if the statement returns a value that matches, the loop will end and return the matched value
    • the loop's return type is the match of the return type of the statement or [] (if the loop ends because the iterator ended)
  • switch
    • switch <var_name> { <arm1> <arm2> <...> }
      • where <armn> is <typen> <statementn>
      • if the variable's value is of type <typen>, <statementn> will be executed.
      • if the variables type is included multiple times, only the first match will be executed.
      • within the statement of an arm, the variables type is that specified in <typen>, and not its original type (which may be too broad to work with)
    • switch! <var_name> { <arm1> <arm2> <...> }
      • same as above, but all types the variable could have must be covered
      • the additional [] in the return type isn't added here since it is impossible not to run the statement of one of the arms.
  • match
    • match <var_name> { <arm1> <arm2> <...> }
      • where <armn> is <statement> <statement>
      • each arm has a condition statement an an action statement.
      • if the value returned by the condition statement matches, the matched value is assigned to the variable and the action statement is executed.
      • only the first matching arm will be executed. if no arm was executed, [] is returned.
  • fixed-indexing
    • <statement>.n where n is a fixed number (not a variable, just 0, 1, 2, ...)
    • <statement> must return a tuple or a reference to one. <statement>.n then refers to the nth value in that tuple.
    • for references to a tuple, references to the inner values are returned.
  • enum
    • <EnumName>: <statement>
  • type definition
    • type <name> <type> (type Message [string string])
  • macros
    • !(<macro_type> <...>)
    • !(mers { <code> })
      • compiles and runs the code at compile-time, then returns the computed value at runtime.
    • !(mers <file_path>) or !(mers "<file path with spaces and \" double quotes>")
      • same as above, but reads code from a file instead
      • path can be relative

Matching

  • values that don't match
    • []
    • false
  • values that match
    • [v] -> v
    • v -> v unless otherwise specified
  • invalid
    • [v1 v2] or any tuple whose length isn't 0 or 1