Skip to content

Latest commit

 

History

History
547 lines (439 loc) · 15.1 KB

language.md

File metadata and controls

547 lines (439 loc) · 15.1 KB

Walnut v0.0.1-pre

This book is the reference for the Walnut configuration language, describes syntax and semantics.

File Format

  • A Walnut file must be encoded in UTF-8.
  • A Walnut file is described as an sequence of statements, and expresses a table by rendering.
  • A Walnut file should use the extension .wal.
  • The appropriate MIME type for Walnut files is application/walnut.

Statement

Statement is a base unit of Walnut, categorized into these types:

Statements basically consist of one line (separated with newline characters), except these cases:

  • Statement with a line ends with \ (without considering whitespaces or comments), will be continued to the next line (and \ will be ignored).
  • Newline characters inside parentheses will be ignored.
  • Newline characters inside strings will be treated by the specific way, determined by the kind of strings, mentioned in the section Expression/String. Note that whitespaces in the beginning or the end of a line and a comment in the end of a line will be ignored (= is equivalent to an empty text).
# All of these are statements.
stmt = "foo"
  stmt2 = "bar"
stmt3 = \
# Empty lines in line continuouses are allowed.
  "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do" + \
  "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
  "minim veniam, quis nostrud exercitation ullamco laboris nisi ut" + \
  "aliquip ex ea commodo consequat. Duis aute irure dolor in" + \
  "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla" + \
  "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in" + \
  "culpa qui officia deserunt mollit anim id est laborum."
stmt4 = [
  "elem1",
  "elem2"
]

Comment

Comment is a text starts with hash symbol (#, U+0023) outside a string, (inside parentheses are allowed) and continues until the appearance of a newline character (not included). Newline characters are not permitted in comments.

# This is an comment
key = "value" # This is also a comment
key2 = "# This is not a comment"

Value Binding

Value Binding is a statement which registers key/value pairs to current scope using patterns. Patterns are on the left of the equals sign (U+003D), and expressions are on the right. Whitespaces around the euqals sign are ignored.

pattern = "expression"

Table Header

Table header is a statement to declare the beginning of table, formed by a pattern surrounded by a pair of square brackets. Whitespaces around the brackets are ignored.

A table header stores an empty table using the pattern (except array and table destructions) using root scope, and starts a new sub scope continues to the next table header or the end of file.

[table1]
key = "value"

  [
  table2
  ]

Overwriting exsiting tables are prohibited.

table = { foo = "foo" }

[table] # Error!

Instead of an empty table, an expression after the closing bracket can be used as an initial tables.

# `table` is `{ foo = "baz", bar = "baz", baz = 1 }`.
[table] { foo = "foo", bar = "bar" }
bar = "baz"   # Overwriting a value.
baz = 1       # Appending a value.

 # It is useful when overwriting an imported table.
[dependencies] import("dependencies.wal")

Array of Tables

By using double square brackets, the header creates an empty array to root scope (in the first header), appends a table to the array, and starts a new sub scope.

[[users]]
name = "Alice"
id = 42362465

[[users]]   # Empty table

[[users]]
name = "Bob"
id = 63328257

# Equivalent to:
users = [
  { name = "Alice", id = 42362465 },
  {},
  { name = "Bob", id = 63328257 },
]

In the first header, an initial array can be used instead of an empty array.

# `array` is `[ { foo = "foo" }, "str", { bar = "bar" }, { baz = "baz" } ]`.
[[array]] [{ foo = "foo" }, "str"]
bar = "bar"

[[array]]
baz = "baz"

Function Definition

Comming soon...

Expression Function

Comming soon...

Table Function

Comming soon...

Expression

Expression is a way to express a value by evaluating literal values or values refered through keys, using operators.

Literal Value

Literal value is a value expressed directly. Literal values are classified to these types:

String

String is an array of characters. There are 4 ways to express strings.

Double Quoted String

Double quoted string starts with a quatation mark (U+0022), ends with a not escaped quatation mark. Any Unicode characters can be used except quatation mark and backslash (U+005C), and escape sequences starts with backslashes can be used:

  • \n ... linefeed (U+000A)
  • \r ... carriage return (U+000D)
  • \t ... horizontal tab (U+0009)
  • \" ... quatation mark (U+0022)
  • \\ ... backslash (U+005C)
  • \ and linefeed (LF), carriage return (CR), or "carriage return and linefeed" (CRLF) ... ignored
  • \xXX ... 8 bit character (U+00XX)
  • \u{XXXX} ... unicode character (U+XXXX)

Note that 8 bit characters are 2-digit hex values, and unicode characters are hex values with 2~8 digits.

string = "The \"Double quated\"\r
\tString"
Single Quoted String

Single quoted string is a string surrounded by two apostrophes (U+0027). No escape sequences are allowed, so apostrophes cannot be included in single quoted strings.

string = '\\ServerX\admin$\system32\'
Double Quoted Unidented String

Double quoted unindented string is similar to double quoted string, but surrounded with triple quotation marks ("""), and will be unindented. Quotation marks can be used in the strings.

# python = "def hello():\n    print('Hello, World!')\n\nhello()"
python = """
    def hello():
        print("Hello, world!")

    hello()
"""
Single Quoted Unindented String

Single quoted unindented string is similar to single quoted string, but surrounded with triple apostrophes ('''), and will be unindented. Apostrophes can be used in the strings.

# python = "def hello():\n    print('Hello, World!')\n\nhello()"
python = '''
    def hello():
        print('Hello, world!')

    hello()
'''

Integer

Integer is a whole number. Decimals, hexadecimals (with prefix 0x), octals (with prefix 0o), and binaries (with prefix 0b) are supported. In hexadecimals, numbers from ten to fifty are expressed by A-F or a-f. Leading zeros are not allowed in decimals.

decimal = 42
hex1 = 0xDEADBEEF
hex2 = 0xcafebabe
oct = 0o644
bin = 0b01010110

An integer prefixed with + will be treated as positive number, one prefixed with - will be treated as negative number. If an integer does not have neither + or -, it will be a positive number. +0, and -0 are identical to 0. Hexadecimal, octal and binary integers cannot have + or - signs.

pos1 = 42
pos1 = +1
zero1 = 0
zero2 = -0
neg = -5

Underscores between digits are allowed for readability.

int1 = 5_349_221
int1 = 1_2_3_4_5
int2 = 0b1101_0110

Accepted range is from -2^63 to 2^63-1 (64bit signed integer).

Float

Float is a IEEE 754 binary64 value.

A float consists of integer part, fractional part and exponent part. An integer part is required, and follows same rule as decimal integer. A fractional part is prefixed with a full stop (U+002E), and consists of one or more decimal digits. An exponent part is prefixed with e or E, and consists of an integer, which follows same rule as decimal integer but leading zeros are allowed. Either a fractional part or an exponent part are required.

A float will be expressed by (i + f) * (10 ** e) where i is an integer part, f is a fractional part prefixed with 0. (if eliminated, f is 0), and e is an exponent part (if eliminated, e is 1).

float1 = 3.14
float2 = +1.23           # same as 1.23
float3 = -0.001
float4 = 3e2             # same as 300.0
float5 = 1e-02           # same as 0.01
float6 = -2E+4           # same as -20000.0
float7 = 5_000.000_003   # same as 5000.000003

Boolean

Boolean is a value, either true or false.

bool1 = true
bool2 = false

Array

Array is a collection of values. An array is surrounded by a pair of square brackets, and values are separated with commas (U+002C). A comma after the last value is allowed, and whitespaces around square brackets or commas will be ignored. See also Array of Tables.

array1 = [1, 2, 3, 4]
array2 = []
array3 = ["foo", true, 2.3]
array4 = [
  "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod",
  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim",
  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea",
  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate",
  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint",
  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt",
  "mollit anim id est laborum."
]

Inline Table

Inline table is another way to express a table. A inline table consists of a list of pairs of a bare or raw key and an expression with a equals sign separater, separated with commas, surrounded by curly brackets. A comma after the last value is allowed, and whitespaces around square brackets or commas will be ignored.

table1 = { foo = "foo", bar = "bar" }
table2 = {}
table3 = {
  string = "foo",
  integer = 42,
  float = 1.0,
  boolean = false,
  array = [0, 1, 2],
  table = { name = "Tom", id = 23235278 },
}

Inline Function

Comming soon...

Key Reference

Comming soon...

Operators

Comming soon...

Arithmetic Operators

Comming soon...

Logical Operators

Comming soon...

Comparison Operators

Comming soon...

Accessing Values

Comming soon...

Function Call

Comming soon...

Tables and Keys

Table

Table is a collection consists of key/value pairs, also known as "dictionary" or "hash map". There are two types to express tables:

[table]
item1 = "item1"
item2 = "item2"

.inline_table = {item1 = "item1", item2 = "item2"}

Key

Key is an identifier refers to a specific value on the table. There are five types of keys:

Bare Key

Bare key is a basic way to express key, and a bare key starts with a english letter (U+0041-U+005A, U+0061-U+007A), and rest characters are consists of english letters, decimal digits (U+0030-U+0039), or low lines (U+005F).

barekey = "This is a bare key."
bare_key2 = "Digits and underscores can be used."

Raw Key

Raw Key is a way to express key contains characters which can't express with bare keys. A raw key starts with a dollar sign (U+0024), and surrounded by a pair of curly brackets. This key can contain any key except backslashes (U+005C) and right curly brackets (U+007D). Escape patterns similar to double quoted strings is available, but instead of \", \} is used to express right curly brackets (U+007D).

Note that bare keys and raw keys consists of same characters (for instance key and ${key}) are identical and will conflict.

${raw key} = "This is a raw key."
${\\{All\u{00A0}characters\ncan be used.\}} = true

Local Key

Local key is a bare or raw key prefixed with a low line (U+005F). Local keys can't be accessed from external scope, and won't be rendered by the compiler. Whitespaces after the _ prefix are ignored.

This is useful when you want to create commonly used in the file, but is not needed to be visible from out of a scope.

base = table._base   # Not allowed
foo = table.foo      # Allowed.

[table]
_base = 5
foo = _base + 5
bar = _base + 10

[table2]
foo = ._base         # Not allowed

_${Raw Local} = "Raw Local Key"
${_Not Local} = "Normal Raw Key"

Refering local keys of outer scopes are allowed.

_root_local = "root"
root1 = _root_local              # Allowed
root2 = sub._sub_local           # Not allowed
root3 = sub.sub._sub_sub_local   # Not allowed

[sub]
_sub_local = "sub"
sub1 = ._root_local              # Allowed
sub2 = _sub_local                # Allowed
sub3 = sub._sub_sub_local        # Not allowed

[sub.sub]
_sub_sub_local = "subsub"
subsub1 = ._root_local           # Allowed
subsub2 = .sub._sub_local        # Allowed
subsub3 = _sub_sub_local         # Allowed

Root Key

Root key is a bare, raw, key prefixed with a period, and access value from the root scope instead of current scope. Whitespaces after . prefix are ignored.

value = "root"

[table]
value = "table"
foo = value          # "table"
bar = .value         # "root"
bar = .table.value   # "table"

.${Raw Root} = "Raw Root Key"
${.Not Root} = "Normal Raw Key"

Function Key

Comming soon...

Scope

Scope is a special table, used as the base point when refering keys. There are three types of scopes:

Root Scope

Root scope is a scope which exists only one per a file, and used as the entry point when rendering the file. Root scopes will be created as an empty table when a file is started.

Sub Scope

Sub scope is a scope created by table headers, and continues to the next table header or the end of file.

Function Scope

Comming soon...

Pattern

Pattern is a way to express destinations of value bindings or table headers.

Key Pattern

Key pattern is a pattern that just stores a key to current scope.

key = "foo"

Dotted Key Pattern

Comming soon...

Array Destruction

Comming soon...

Table Destruction

Comming soon...

Terms

  • "Whitespace" means tab (U+0009) or space (U+0020).
  • "Newline" means a string sequence starts with line feed (U+000A) or carriage return (U+000D), and contains only tabs, spaces, line feeds, carriage returns or comments.
  • "Parenthesis" means left and right of round brackets (()), curly brackets ({}), or square brackets ([]).
  • "Render" means processing and converting the walnut file to other data notations.

ABNF Grammar

Comming soon...