Skip to content

Platypus Grammar


Below is the syntax definition for the Platypus language used by the Pipeline processor. With the gradual support of different syntaxes, this document will be adjusted and added or deleted to varying degrees.

Identifier and Keyword

Identifier

Identifiers are used to identify objects and can be used to represent a variable, function, etc. The identifier contains keywords; the custom identifier cannot be repeated with the keywords of the Pipeline data processor language;

Identifiers can be composed of numbers (0-9), letters (A-Z a-z), and underscores (_), but the first character cannot be a number and is case-sensitive:

  • _abc
  • abc
  • abc1
  • abc_1_

Use backticks if you need to start with a non-alphabet or non-underscore, or use characters other than the above in the identifier:

  • `1abc`
  • `@some-variable`
  • ` 这是一个表情包变量👍`

special agreement

We agree to use the identifier _ to represent the input data of the Pipeline data processor, and this parameter may be implicitly passed to some built-in functions;

To maintain forward compatibility, _ will be treated as an alias for message when used in the current version.

Keyword

Keywords are words with special meaning, such as if, elif, else, for, in, break, continue, nil, etc. These words cannot be used as variables or constants or the name of a function etc.

Comments

Use # as line comment character, inline comment is not supported

# This is a line comment
a = 1 # this is a comment line

"""
This is a (multiline) string that replaces comments
"""
a = 2

"comments"
a = 3

Built-in Data Types

In Platypus, the Pipeline data processor language, by default, the type of the value of a variable can change dynamically, but each value has its data type, which can be one of the basic types or composite type

When a variable is not assigned a value, its value is nil, which means no value.

Basic Type

Integer (int) Type

Integer type length is 64bit, signed, currently only supports writing integer literals in decimal format, such as -1, 0, 1, +19

Floating Point (float) Type

The length of the floating-point type is 64bit, signed, and currently only supports writing floating-point literals in decimal, such as -1.00001, 0.0, 1.0, +19.0

Boolean (bool) Type

Boolean literals only have true and false

String (str) Type

String literals can be written with double quotes or single quotes, and multi-line strings can be written using triple double quotes or triple single quotes

  • "hello world"
  • 'hello world'
  • Use """ to express multi-line strings
"""hello
world"""
  • Use ''' to express multi-line strings
'''
hello
the world
'''

Composite Type

The map type and list type are different from other types. Multiple variables can point to the same map or list object. The memory copy of the list or map is not performed during assignment, but the memory address of the map/list value is referenced.

Map Type

The map type is a key-value structure. (Currently) only the string type can be used as a key, and the data type of the value is not limited.

It can read and write elements in the map through index expressions:

a = {
   "1": [1, "2", 3, nil],
   "2": 1.1,
   "abc": nil,
   "def": true
}

# Since a["1"] is a list object, b just refers to the value of a["1"]
b = a["1"]

"""
At this point a["1"][0] == 1.1
"""
b[0] = 1.1

List Type

The list type can store any number of values of any type in the list.

It can read and write elements in the list through index expressions:

a = [1, "2", 3.0, false, nil, {"a": 1}]

a = a[0] # a == 1

Operator

The following operators are currently supported by Platypus, and the higher the value, the higher the priority:

Priority Symbol Associativity Description
1 = right assignment; named argument; lowest precedence
1 += right assignment, left operand = left operand + right operand
1 -= right assignment, left operand = left operand - right operand
1 *= right assignment, left operand = left operand * right operand
1 /= right assignment, left operand = left operand / right operand
1 %= right assignment, left operand = left operand % right operand
2 || left logical "or"
3 && left Logical AND
4 in left Determine whether the key is in the map; Specify the element in the list; The substring is included in the string
5 >= left condition "greater than or equal to"
5 > left condition "greater than"
5 != left condition "not equal to"
5 == left condition "equal to"
5 <= left condition "less than or equal to"
5 < left condition "less than"
6 + left arithmetic "plus"
6 - left arithmetic "minus"
7 * left arithmetic "multiply"
7 / left arithmetic "division"
7 % left arithmetic "remainder"
8 ! right unary operator; logical "negation", available for 6 built-in data types
8 + right unary operator; positive sign, can be used to represent positive numbers
8 - right unary operator; minus sign, used to flip the sign and represent negative numbers
9 [] left Subscript operator; can use list subscript or map key to get value
9 () left Can change operator precedence; function call

Expression

Platypus uses the symbol comma , as the expression separator, such as the parameter transfer used to call the expression and the expression when the map and list are initialized.

In Platypus, expressions can have values, but statements must not have values, that is, statements cannot be used as the left and right operands of operators such as =, but expressions can.

Literal Expression

Literals of various data types can be used as expressions, such as integers 100, -1, 0, floating-point numbers 1.1, Boolean values true, false, etc.

The following two are literal expressions of composite types:

  • List literal expression
[1, true, "1", nil]
  • Map literal expression
{
   "a": 1,
   "b": "2",
}

Call Expression

The following is a function call to get the number of list elements:

len([1, 3, "5"])

Binary Expression

Binary expressions consist of binary operators and left and right operands.

The current version of the assignment expression is a binary expression, which has a return value; but because the assignment expression may cause some problems, this syntax will be deleted in the future, and the assignment statement syntax will be added.

#0
2 out of 5

# 0.4, promote the type of the left operand to a floating-point number during calculation
2 / 5.0

#true
1 + 2 * 3 == 7 && 1 <= 2


# a = (b = 3), a == 3 due to the right associativity of the `=` operator
b == 3;
a = b = 3

# Note: Since the assignment expression syntax is about to be abolished, please replace it with an assignment statement
b = 3
a = b

"a"   in  [1,"a"]   # true
"def" in  "abcdef"  # true
"a"   in  {"a": 1}  # true
"b"   in  {"a": 1}  # false

x = 1; y= [1]
x in y  # true

Index Expression

Index expressions use the [] subscript operator to operate on the elements of a list/map.

The elements of list or map can be valued or modified and elements can be added to the map through index expressions. For lists, negative numbers can be used for indexing.

Syntax example:

a = [1, 2 ,3, -1.]
b = {"a": [-1], "b": 2}

a[-1] = -2
b["a"][-1] = a[-1]

# result
# a: [1,2,3,-2]
# b: {"a":[-2],"b":2}

Bracket Expression

Bracket expressions can change the precedence of operand operations in binary expressions, but not associativity:

# 1 + 2 * 3 == 7

(1 + 2) * 3 # == 9

Statement

All expressions in Platypus can be regarded as value statements. When an expression ends with a statement delimiter ; or \n, it will be regarded as a statement. For example, the following script contains four statements:

len("abc")
1
a = 2; a + 2 * 3 % 2

Value Statement (expression statement)

When an expression is followed by a statement delimiter, it can be regarded as a value statement. The following are four legal statements:

# floats as statements
1.;

# function call expression as statement
len("Hello World!"); len({"a": 1})

# identifiers as statements
abc

Assignment Statement

Syntax example:

key_a = "key-a"

# The identifier a is used as the left operand, assigning a a list literal
a = [1, nil, 3]

# index expression as left operand
a[0] = 0
a[2] = {"key-b": "value-b"}
a[2][key_a] = 123

Select Statement

Platypus supports if/elif/else syntax:

if condition {

}
if condition {

} else {

}
if condition_1 {

} elif condition_2 {

} ... elif condition_n {

} else {

}

Same as most programming languages, enter the corresponding statement block according to whether the condition of if/elif is true, or enter the else branch if it is not true.

The current condition can be any expression, as long as its value is one of the built-in data types, when its value is the default value of the type, the expression value is flase:

  • When the condition is an int type value, it is 0 then the condition is false, otherwise it is true
  • When the condition is a float type value, it is 0.0 then the condition is false, otherwise it is true
  • When the condition is a string type value, it is an empty string "" then the condition is false, otherwise it is true
  • when the condition is a bool type value, the condition is the current value
  • When the condition is a value of type nil, the condition is false
  • When the condition is a map type value, its length is 0 then the condition is false, otherwise it is true
  • When the condition is a list type value, its length is 0 then the condition is false, otherwise it is true

Loop Statement

Platypus supports for statement and for in statement.

The following are two statements that are only allowed in a loop block:

  • cotinue statement, do not execute subsequent statements, continue to start the next cycle
  • The break statement, which ends the loop

When using the for statement, it may cause an infinite loop, so it should be used with caution, or use the for in statement instead.

for init-expr; condition; loop-expr {

}
for varb_name in map_value/list_value/string_value {

}

Example usage:

  • Use for to execute 10 loops:
for a = 0; a < 10; a = a + 1 {

}
  • Use for in to iterate over all elements of the list:
b = "2"
for a in ["1", "a" ,"2"] {
  b = b + a
  if b == "21a" {
    break
  }
}
# b == "21a"
  • use for in to iterate over all keys of the map:
d = 0
map_a = {"a": 1, "b": 2}
for x in map_a {
  d = d + map_a[x]
}
  • use for in to iterate over all characters of string:
s = ""
for c in "abcdef" {
  if s == "abc" {
    break
  } else {
    continue
  }
  s = s + "a"
}
# s == "abc"

Feedback

Is this page helpful? ×