From e04af86491d97b297406cc4cd0d77fbbfc3a94c4 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 16 May 2024 17:40:34 -0700 Subject: docs: update website --- docs/book/SYNTAX.html | 330 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 247 insertions(+), 83 deletions(-) (limited to 'docs/book/SYNTAX.html') diff --git a/docs/book/SYNTAX.html b/docs/book/SYNTAX.html index 6aa71e8..a241b74 100644 --- a/docs/book/SYNTAX.html +++ b/docs/book/SYNTAX.html @@ -7,7 +7,7 @@ - + @@ -174,40 +174,212 @@

Syntax: A Casual and Formal Look

-
-

! This section is incomplete. Proceed with caution.

-
+

Call Syntax

+

There is little difference between a function, macro, and operator call. There are only a few forms such calls can take, too, though notably more than most other languages (due to, among other things, uniform function call syntax): hence this section.

+
# The standard, unambiguous call.
+routine(1, 2, 3, 4)
+# The method call syntax equivalent.
+1.routine(2, 3, 4)
+# A block-based call. This is only really useful for macros taking in a body.
+routine
+  1
+  2
+  3
+  4
+# A parentheses-less call. This is only really useful for `print` and `dbg`.
+# Only valid at the start of a line.
+routine 1, 2, 3, 4
+
+

Binary operators have some special rules.

+
# Valid call syntaxes for binary operators. What can constitute a binary
+# operator is constrained for parsing's sake. Whitespace is optional.
+1 + 2
+1+2
++ 1, 2 # Only valid at the start of a line. Also, don't do this.
++(1, 2)
+
+

As do unary operators.

+
# The standard call for unary operators. Postfix.
+1?
+?(1)
+
+

Method call syntax has a number of advantages: notably that it can be chained: acting as a natural pipe operator. Redundant parenthesis can also be omitted.

+
# The following statements are equivalent:
+foo.bar.baz
+foo().bar().baz()
+baz(bar(foo))
+baz
+  bar
+    foo
+baz bar(foo)
+baz foo.bar
+
+

Indentation Rules

+

The tokens =, then, do, of, else, block, const, block X, and X (where X is an identifier) are scope tokens. They denote a new scope for their associated expressions (functions/macros/declarations, control flow, loops). The tokens ,, . (notably not ...), and all default binary operators (notably not not) are continuation tokens. An expression beginning or ending in one of them would always be a syntactic error.

+

Line breaks are treated as the end of a statement, with several exceptions.

+
pub func foo() =
+  print "Hello, world!"
+  print "This is from a function."
+
+pub func inline_decl() = print "Hello, world!"
+
+

Indented lines following a line ending in a scope token are treated as belonging to a new scope. That is, indented lines following a line ending in a scope token form the body of the expression associated with the scope token.

+

Indentation is not obligatory after a scope token. However, this necessarily constrains the body of the associated expression to one line: no lines following will be treated as an extension of the body, only the expression associated with the original scope token. (This may change in the future.)

+
pub func foo(really_long_parameter: ReallyLongType,
+another_really_long_parameter: AnotherReallyLongType) = # no indentation! this is ok
+  print really_long_parameter # this line is indented relative to the first line
+  print really_long_type
+
+

Lines following a line ending in a continuation token (and, additionally not and () are treated as a continuation of that line and can have any level of indentation (even negative). If they end in a scope token, however, the following lines must be indented relative to the indentation of the previous line.

+
let really_long_parameter: ReallyLongType = ...
+let another_really_long_parameter: AnotherReallyLongType = ...
+
+really_long_parameter
+  .foo(another_really_long_parameter) # some indentation! this is ok
+
+

Lines beginning in a continuation token (and, additionally )), too, are treated as a continuation of the previous line and can have any level of indentation. If they end in a scope token, the following lines must be indented relative to the indentation of the previous line.

+
pub func foo() =
+  print "Hello, world!"
+pub func bar() = # this line is no longer in the above scope.
+  print "Another function declaration."
+
+

Dedented lines not beginning or ending with a continuation token are treated as no longer in the previous scope, returning to the scope of the according indentation level.

+
if cond then this
+else that
+
+match cond
+of this then ...
+of that then ...
+
+

A line beginning with a scope token is treated as attached to the previous expression.

+
# Technically allowed. Please don't do this.
+let foo
+= ...
+
+if cond then if cond then this
+else that
+
+for i
+in iterable
+do ...
+
+match foo of this then ...
+of that then ...
+
+match foo of this
+then ...
+of that then ...
+
+

This can lead to some ugly possibilities for formatting that are best avoided.

+
# Much preferred.
+
+let foo =
+  ...
+let foo = ...
+
+if cond then
+  if cond then
+    this
+else that
+if cond then
+  if cond then this
+else that
+
+for i in iterable do
+  ...
+for i in iterable do ...
+
+match foo
+of this then ...
+of that then ...
+
+

The indentation rules are complex, but the effect is such that long statements can be broken almost anywhere.

+

Expression Rules

+

First, a word on the distinction between expressions and statements. Expressions return a value. Statements do not. That is all.

+

There are some syntactic constructs unambiguously recognizable as statements: all declarations, modules, and use statements. There are no syntactic constructs unambiguously recognizable as expressions. As calls returning void are treated as statements, and expressions that return a type could possibly return void, there is no explicit distinction between expressions and statements made in the parser: or anywhere before type-checking.

+

Expressions can go almost anywhere. Our indentation rules above allow for it.

+
# Some different formulations of valid expressions.
+
+if cond then
+  this
+else
+  that
+
+if cond then this
+else that
+
+if cond
+then this
+else that
+
+if cond then this else that
+
+let foo =
+  if cond then
+    this
+  else
+    that
+
+
# Some different formulations of *invalid* expressions.
+# These primarily break the rule that everything following a scope token
+# (ex. `=`, `do`, `then`) not at the end of the line must be self-contained.
+
+let foo = if cond then
+    this
+  else
+    that
+
+let foo = if cond then this
+  else that
+
+let foo = if cond then this
+else that
+
+# todo: how to handle this?
+if cond then if cond then that
+else that
+
+# shrimple
+if cond then
+  if cond then that
+else that
+
+# this should be ok
+if cond then this
+else that
+
+match foo of
+this then ...
+of that then ...
+

Reserved Keywords

The following keywords are reserved:

+

The following keywords are not reserved, but liable to become so.

- -

The following identifiers are in use by the standard prelude:

- - -- cgit v1.2.3-70-g09d2