You may also want to have a look at syntax choices explained
The various tokens:
- constants/special variables are capitalized: X, Math, True, HERE [1]
- variables: x, i, sort!, bool?, x', _ [2]
- integers: 123, 0xfa, 987 [3]
- floats: 1.2, 0.1e-2, .222 [4]
- strings: "[^"]*" or q(...) or qq(...)
- to determine where q(...) and qq(...) ends, a simple balanced parentheses expression is used (think perl)
eg: q(this (should) end here)
- multi-lines strings are allowed.
- in "..." and qq(...), expressions enclosed in {...} are meant to be
interpreted: "1+1 is {1+1}" will give "1+1 is 2"
- operators: ( ) [ ] { } , . .. :: and [&~-|`\^@=+$%*!/:;?<>']+
- indentation: beginning of line blanks are used for layout (see Parser)
- spaces: one or more space is the same (see Parser)
- comments: text from # until the end of the line is ignored
Merd's syntax dynamicity rules out any classical parsing.
- method calling notation
object.method <=> method(object)
object.method(l) <=> method(object,l)
is true everywhere
- merd source files should not contain tabulations ("\t"). If you want to use
tabulations anyway, the tabsize must be given using Pragma::tabsize
which the tabsize for current block
- parentheses are used for
- function and method calls
- grouping expressions together
- ability to declare operators fixity and priority
Pragma::separator(-13,;)
Pragma::infixr(-15,->)
Pragma::infix(-14,if)
Pragma::prefix(-16,if then else)
Pragma::around([ ])
Pragma::suffix(40,++)
- "if then else" is a multiple operator (think smalltalk)
- an operator can be infix, suffix and prefix, given that the priority is the
same
- missing operands introduces ``holes'': + 1 <=> Builtin::Hole + 1
- a separator at the end of the line that would generate a hole is removed
(
1,
2,
)
<=> (1,2)
whereas (1,2,) <=> (1,2,Builtin::Hole)
- separators (mainly , and ;) are used to create lists of different kinds.
- around-ops sticked after an expression are automatically suffix operators
- indentation based grouping: merd completly generalizes the layout scheme found in haskell (and even more python's).
aaaaa
bbb
c is the same as (aaaaa ; (bbb ; (c) ; (c))) ; (aaaaa)
c
aaaaa
aaaaa +
bbb is the same as (aaaaa + (bbb)) (with + being declared infix!)
- horizontal grouping: different tokens together with no spaces in between are ``grouped''.
eg: A@B @D <=> (A@B)@D, 1+2 * 3 <=> (1+2)*3
- :: is used for explicit package scope
- "," tuple (n-ary operator)
- ";" sequence (n-ary operator)
- ":=", "=" 2 assignment/declaration operators are available, with different priorities.
- "->" anonymous function operator / ML pattern matching
- "." method call operator
- "::" explicit package scope
- "{ ... }" record selector
- "!!", "!<", "!>" type operators
- "+" number summation / list & string concatenation
- "||", "&&" logical or/and (Bool,Bool -> Bool)
- "|" type variant constructor
- "|&|" function overloading / record constructor
- "==", "!=" equality / inequality
- "<", ">", "<=", ">=", "<=>" comparison
Full list of operators including their priority
e1 = f(x)
e1' = x.f
e2 = f(x,y)
e2' = x.f(y)
e1 and e1' are equivalent function calls. Same for
e2 and e2': no distinction between method and function is
done.
Partial application
Partial application is achieved using holes (choice explaination)
gcd10 = gcd(10,)
gcd10' = x -> gcd(10,x)
gcd10'' = x -> 10.gcd(x)
bad_gcd10 = 10.gcd #=> missing parameter
bad_gcd10' = 10.gcd() #=> () is not a number
Multi-methods
Method dispatching is done based on all parameters.
merd's polymorphism explains this.
Mutators and predicates
- functions of the form xxx? are predicates
- functions of the form xxx! are mutators
This is a convention (it may change). It means xxx? returns a boolean, and xxx! returns Unit
(alike void).
This syntax feature is taken from Scheme and Ruby. But contrary to Scheme,
identifier of the form xxx!xxx are not allowed (alike Ruby).
Things like xxx!? are mutators that may fail, returning a boolean telling
success or error (one could also have a mutator xxx! throwing an exception,
but usability differs)
Parameter variables
Function with parameters create new variables having the function scope:
f(x) = x
# x now out of scope
f = x->x
# x now out of scope
Local variables
New local variables are declared when initialised. Their scope ends when the current
block ends [5]:
f(x) =
i = "i"
if cond then
k = "k1"
# k now out of scope
else
k = "k2"
# k now out of scope
l =
m = "m"
n = "n"
m+n
# m,n now out of scope
o = (p = "p" ; p)
# i,l,o,x,f still accessible
Capitalized tokens are usually constants. But they can be special
variables, usually used as type variables [6].
A capitalized token is a special variable if:
- it is alone on the left side of a declaration.
eg: Bool is a variable in Bool = True | False
- a declaration as above is in scope (using the same block scoping as normal local variables)
A special variable do not behave like a normal variable when used in function
parameters and pattern matching:
bool = True | False
f !! bool -> bool
do not behave as wanted, here the type of f is set to bool -> bool
which is the same as a -> a (alpha-renaming)
Bool = True | False
g !! Bool -> Bool
works as wanted, Bool being replaced by its value, the type of
f is set to True|False -> True|False.
Notes
[1] The regexp for constants truly is [A-Z]\w*[!?']*
[2] The regexp for variables truly is [a-z_]\w*[!?']*
[3] The regexp for integers truly is ([0-9]+ or 0x[0-9a-fA-F]+)
[4] Beware, 2. is not a float otherwise it would conflict with method call: 2.sqrt
[5]
Python's blocks do not introduce any scope, variables being function-wide.
Block scoped variable gets in the way with languages where the only way to
declare variables is affectation.
For example, with block scoped variable you can't write this anymore:
if cond:
i = 1
else
i = 2
This can be work-arounded with functional oriented syntax:
i =
if cond:
1
else:
2
but that's no more python :)
[6] special variables are necessary because of the lack of a special type namespace
Pixel
This document is licensed under GFDL (GNU Free Documentation License).
Release: $Id: syntax.html,v 1.17 2002/05/17 15:22:56 pixel_ Exp $