nim manual(一)

原文链接:http://nim-lang.org/docs/manual.html#lexical-analysis

作者:Andreas Rumpf, Zahary Karadjov

版本:0.11.2


"Complexity" seems to be a lot like "energy": you can transfer it from the end user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran


"复杂性"似乎很像"能量":你可以将它从终端用户传递到一个或其他一些用户,但是对于一个给定的任务总量保持相当恒定.--Ran

关于这个文档

注意:这个文档是一个草案!一些nim的特点需要更精确的词语。在将来的某一天这个手册将会逐渐演变成一个适当的规范。

这个文档描述了nim的词汇,语法,以及语义。


nim的语言结构用扩展巴科斯-瑙尔范式(BNF)解释,(a)*意味着零个或多个a's,a+意味着一个或多个a's,以及(a)?意味着一个a的选择。圆括号可以用来将元素分组。


(注:我自己认为(a)*代表a经过零步或者多步扩展,a+代表a经过一步或者多步扩展)


&是前缀运算符;&a意味着一个a是预期中的但不消耗.在下列规则中它将被消耗.(这句话翻译的更让人迷惑,恕我能力有限,如有更好的解释,欢迎指导)


|,/符号用于标记选择,它们有最低的优先级。/是有序选择它要求解析器尝试以给定的顺序选择。/经常用来确保语法不是模糊不清的。


非终结符以一个小写字符开始,抽象终结符号用大写字母表示。逐字的终结符号(包括关键字)用'括起来。一个例子:

ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?


二元操作符^*被用作被它的第二个参数分开的0个或者多个事件的一个简写;同样的,^+意味着1个或更多事件,a ^+ b短于a (b a)*并且a ^* b短于(a (b a)*)?例如:

arrayConstructor = '[' expr ^* ',' ']'

nim其他的部分-比如作用域规则或者运行时语义暂时用一种非正式方式进行描述。


Definitions

nim程序指定一个计算作用于组件组成的内存叫做位置。一个变量基本上是一个位置的名称。每一个变量和位置都是一个特定的类型。变量的类型叫做静态类型,位置的类型叫做动态类型。如果静态类型与动态类型不一致,静态类型是动态类型的一个超类型或者子类型。


一个标识符是一个符号,声明作为一个变量,类型,过程的名字,等。在程序中一个声明作用的地区称为声明的作用域。作用域可以嵌套。一个标识符的含义是由这个标识符声明的最小封闭范围决定,除非有另外的重载解析规则建议。


一个表达式指定一个计算产生一个值或者位置。表达式产生的位置称为l-values(左值)。一个l-values可以表示一个位置或者位置包含的值,根据上下文。表达式的值可以静态确定的称为常量表达式;它们绝不是l-values。


一个静态错误是一个在程序执行之前实施检测的错误。除非明确分类,一个错误是一个静态错误。


一个检查运行错误是一个在运行时实施检测和报告的错误。报告这样错误的方法是通过引发异常或者带有一个重大错误的死亡。然而,实现提供了一种方式来禁用这些运行时检查。详细内容见编译部分。


一个检查运行时错误是否导致一个异常或者在运行时发生一个重大错误是具体实施的。因此下面的程序总是无效的:

var a: array[0..1, char]
let i = 5
try:
  a[i] = 'N'
except IndexError:
  echo "invalid index"

一个未检查运行时错误是一个不能保证被发现以及会造成后续的计算结果是任意的错误。如果仅使用安全语言的特征未检查运行时错误不会发生。


词法分析

编码

所有nim源文件都使用UTF-8编码(或它的子集ASCII码)。不支持其他编码。可以使用任意标准的平台终止序列-使用ASCII LF的UNIX形式(换行),使用ASCII CR LF序列的Windows形式(回车加换行),或使用ASCII CR字符(回车)的旧的Macintosh形式,忽视平台,所有这些形式可以平等的使用。

缩进

nim的标准语法描述了一种缩进敏感语言。这意味着所有的控制结构通过缩进被识别。缩进仅包括空格,制表符是不允许的。


缩进处理实现如下:词法分析器解释随后的标记前面的空格数;缩进不是一个分开的标记。这个诀窍允许只用一个预读标记解析nim。


解析器使用一个有缩进级别的堆栈:堆栈由整数计数空间组成。缩进的信息在解析器的战略位置查询,但是忽略其他的解析器;伪终端IND{>}指出一个缩进包含更多的空格相比位于堆栈顶部入口的缩进;IND{=}指出一个缩进包含的空格数与位于堆栈顶部入口的缩进相等。DED是另一个伪终端描述从栈顶弹出一个值的作用,IND{>}意味着推入堆栈。


通过这种符号,现在我们可以很容易地定义语法的核心:一个语句块(简化的例子):

ifStmt = 'if' expr ':' stmt
         (IND{=} 'elif' expr ':' stmt)*
         (IND{=} 'else' ':' stmt)?

simpleStmt = ifStmt / ...

stmt = IND{>} stmt ^+ IND{=} DED  # list of statements
     / simpleStmt                 # or a simple statemen

注释

注释使用哈希字符#开始在一个字符串或者字符外的任何地方。注释由注释片串联组成。一个注释片开始于#,直到这一行的结束。结束字符属于注释片。如果下一行仅仅由一个与前面的一个注释片之间没有其他标记的注释片组成,它不开始一个新的注释。

i = 0     # This is a single comment over multiple lines.
  # The scanner merges these two pieces.
  # The comment continues here.

文档注释由##开始。文档注释是标记;它们只允许在输入文件的特定位置,因为它们属于语法树!


标识符 & 关键字

在nim中标识符可以是任何的字母,数字以及下划线组成的字符串,必须以字母开始。两个相连接的下划线__是不允许的。

letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
digit ::= '0'..'9'
IDENTIFIER ::= letter ( ['_'] (letter | digit) )*

目前任何序数值>127(非ASCII)的unicode字符被归类为一个字母,因此可能作为标识符的一部分,但是以后的语言版本可能会分配一些unicode字符属于操作符字符。

下面的关键字被保留,不能作为标识符:

addrandasasmatomicbindblockbreakcasecastconceptconstcontinueconverterdeferdiscarddistinctdivdoelifelseendenumexceptexportfinallyforfromfuncgenericifimportinincludeinterfaceisisnotiteratorletmacromethodmixinmodnilnotnotinobjectoforoutprocptrraiserefreturnshlshrstatictemplatetrytupletypeusingvarwhenwhilewithwithoutxoryield


一些关键字被闲置,为了未来语言的发展它们被保留。


标识符相等

两个标识符被认为是相等的如果下面的算法返回true:

proc sameIdentifier(a, b: string): bool =
  a[0] == b[0] and a.replace("_", "").toLower == b.replace("_", "").toLower

这意味着仅仅第一个字符用区分大小写的方式比较,其他字符比较不区分大小写以及忽视下划线。


这种奇特的方式做比较,称为部分标识符不区分大小写,具有一定的优势,相比传统的大小写敏感:


它允许程序员大多使用自己喜欢的拼写方式,由不同的程序员编写的库不能使用不兼容的公约。一个Nim-aware编辑器或者IDE显示首选的标识符。另一个优点是,他将程序员从记住确切标识符的拼写中解放出来。对于第一个字符要尊敬的例外是允许公共代码如:var foo:Foo被精确解析。


从历史上看,nim是不敏感的语言风格。这意味着它不区分大小写,下划线被忽视,foo与Foo之间没有歧义。


字符串字面量

语法中的终结符:STR_LIT。

字符串可以通过匹配的双引号分割,以及可以包含下列的转移字符:


Escape sequence Meaning
\nnewline
\r\ccarriage return
\lline feed
\fform feed
\ttabulator
\vvertical tabulator
\\backslash
\"quotation mark
\'apostrophe
\ '0'..'9'+character with decimal value d; all decimal digits directly following are used for the character
\aalert
\bbackspace
\eescape [ESC]
\x HHcharacter with hex value HH; exactly two hex digits are allowed

在nim中字符串可以包含任何8位值,甚至嵌入零。然而,某些操作可能解释第一个二进制零作为一个终结符。


三引号字符串

在语法中的终结符号:TRIPLESTR_LIT。

字符串字面值也可以通过三引号分割""" ... """。这种形式的字面值可能会占用几行,可能包含",以及不解释任何转义序列。方便起见,当开始的"""紧跟一个换行符(在开始的"""和换行符之间可能有空格),换行符(以及前面的空格)不包含在字符串中。结尾的字符串通过模式"""[^"]定义,因此:

""""long string within quotes""""
Produces:
"long string within quotes"



原始字符串字面量

语法中的终结符:RSTR_LIT。

这也有原始字符串字面量,它有前导字母r(或者R)以及通过匹配双引号分割(就像是普通的字符串),不解释转义序列。对于正规表达式或者windows路径是特别方便的:

var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab

为了在一个原始字符串字面值中产生一个单独的",它必须是成对的:

r"a""b"
Produces:
a"b

r""""这种符号是不可能的,因为三个领先的引号产生一个三引号字符串字面量。r"""与"""是一样的,因此三引号字符串字面量也不解释转义字符序列。


广义的原始字符串字面量

语法中的终端符号:GENERALIZED_STR_LIT, GENERALIZED_TRIPLESTR_LIT。

构造identifier"string literal"(在标识符与开始标记之间没有空格)是一个广义的原生字符串。它是构造identifier(r"string literal")的一个简写,所以它代表一个过程调用,带有一个原生字符串字面量作为它的唯一的参数。对于直接在nim中嵌入微语言广义的原生字符串特别方便。(例如正则表达式)。

构造identifier"""string literal"""也是存在的。它是identifier("""string literal""")的一个简写。


字符字面量

字符字面值用单引号括起'',并且它可以与字符串包含相同的转义序列-只有一个例外:换行符(\n)是不允许的,因为它可以多于一个字符(例如,通常是双字符CR/LF)。这是字符字面量有效转移序列:

Escape sequence Meaning
\r\ccarriage return
\lline feed
\fform feed
\ttabulator
\vvertical tabulator
\\backslash
\"quotation mark
\'apostrophe
\ '0'..'9'+character with decimal value d; all decimal digits directly following are used for the character
\aalert
\bbackspace
\eescape [ESC]
\x HHcharacter with hex value HH; exactly two hex digits are allowed

一个字符不是一个Unicode字符而是一个单字节。这样做的原因是效率:在绝大多数使用情况下,由此产生的程序仍将正确的处理UTF-8,因为UTF-8是专门为这设计的。另一个原因是nim可以有效的支持array[char,int]或者set[char],因为很多的算法依赖于这个特性。Rune type用于Unicode字符,它可以代表任何Unicode字符。Rune在unicode模块中声明。


数值常量

数值常量是一个单一的类型,有这样的形式:

hexdigit = digit | 'A'..'F' | 'a'..'f'
octdigit = '0'..'7'
bindigit = '0'..'1'
HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
DEC_LIT = digit ( ['_'] digit )*
OCT_LIT = '0o' octdigit ( ['_'] octdigit )*
BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*

INT_LIT = HEX_LIT
        | DEC_LIT
        | OCT_LIT
        | BIN_LIT

INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8'
INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16'
INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'

UINT_LIT = INT_LIT ['\''] ('u' | 'U')
UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64'

exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent)
FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32'
            | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32'
FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64'
            | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64'

从展示中可以看到,为了可读性数值常量可以包含下划线。整形和浮点型给出十进制(无前缀),二进制(前缀0b),八进制(前缀0o)以及十六进制(前缀0x)标记。

对于每一种定义的数值类型存在一个字面值。以(''')开始的后缀被称作一个类型后缀。没有一个类型后缀的是整形,除非字面量包含一个点或者E|e,在这种情况下它是浮点类型。为方便起见,如果它没有歧义,一个后缀类型的撇号是可选择的。(只有十六进制浮点数带有一个类型后缀是有歧义的)

The type suffixes are:

Type Suffix Resulting type of literal
'i8int8
'i16int16
'i32int32
'i64int64
'uuint
'u8uint8
'u16uint16
'u32uint32
'u64uint64
'f32float32
'f64float64

浮点字面量也可以有二进制,八进制或者十六进制符号:0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64大约是1.72826e35根据IEEE浮点标准。


操作符

在nim中可以定义自己的操作符。一个操作符是以下字符的任意组合:

=     +     -     *     /     <     >
@     $     ~     &     %     |
!     ?     ^     .     :     \

这些关键字也是操作符:and or not xor shl shr div mod in notin is isnot of。

=, :, ::不能作为一般的操作符;它们被用于其他符号的用途。

*:是作为一个特殊的情况两个标记*和:(支持var v*:T)。


其他符号

下面的字符串表示其他的标记:

`   (     )     {     }     [     ]     ,  ;   [.    .]  {.   .}  (.  .)

片操作符..优先与其他包含一点:{..}是三标记{, .., }而不是两标记{., .}的标记。


句法

这部分列出了nim的标准语法。解析器如何处理缩进已经在Lexical Analysis部分做了描述。

nim允许用户自定义操作符。二元操作符有11个不同层次的优先级。


结合性

第一个字符是^的二元操作符是右结合性,其他所有二元操作符都是左结合性。


优先级

一元运算符的结合性强于任何二元运算符:$a + b是($a) + b不是$(a + b)。


如果一个一元运算符的第一个字符是@,它是一个sigil-like操作符,它的结合性强于一个primarySuffix(首要后缀):@x.abc被解析为(@x).abc,反之,$x.abc被解析为$(x.abc)。


对于不是关键字的二元运算符,它的优先级由以下规则判定:

操作符以任何一个类似箭头状的->,~>,=>结束,它在所有的操作符中有最低的优先级。

如果操作符以=结束并且它的第一个字符不是<, >, !, =, ~, ?中的任何一个,它是一个具有二次最低优先级的赋值运算符。


否则,优先级通过第一个字符决定。

Precedence level Operators First character Terminal symbol
10 (highest) $ ^OP10
9* / div mod shl shr %* % \ /OP9
8+ -+ - ~ |OP8
7&&OP7
6...OP6
5== <= < >= > != in notin is isnot not of= < > !OP5
4and OP4
3or xor OP3
2 @ : ?OP2
1assignment operator (like +=*=) OP1
0 (lowest)arrow like operator (like ->=>) OP0

强空格

一个非关键字操作符前面的空格数影响优先级如果使用实验解析指令#!strongSpaces。缩进不用来确定空格数。如果2个或更多的操作符有相同数量的前置空格,优先表适用,所以1 + 3 * 4仍然被解析为1 + (3 * 4),但是1+3 * 4被解析为(1+3) * 4:

#! strongSpaces
if foo+4 * 4 == 8  and  b&c | 9  ++
    bar:
  echo ""
# is parsed as
if ((foo+4)*4 == 8) and (((b&c) | 9) ++ bar): echo ""

此外,操作者是否使用一个前缀操作符是受空格数的影响:

#! strongSpaces
echo $foo
# is parsed as
echo($foo)

这也影响到[], {}, ()是被解析为构造器或者访问器:

#! strongSpaces
echo (1,2)
# is parsed as
echo((1,2))

只有0, 1, 2, 4或者8空格允许限定优先级并且它强调中缀运算符前后有相同数量的空格。这个规则不适用于操作符后有一换行,只考虑前面的空格。


语法

语法的开始符号是模块。

module = stmt ^* (';' / IND{=})
comma = ',' COMMENT?
semicolon = ';' COMMENT?
colon = ':' COMMENT?
colcom = ':' COMMENT?
operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
         | 'or' | 'xor' | 'and'
         | 'is' | 'isnot' | 'in' | 'notin' | 'of'
         | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
prefixOperator = operator
optInd = COMMENT?
optPar = (IND{>} | IND{=})?
simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
arrowExpr = assignExpr (OP1 optInd assignExpr)*
assignExpr = orExpr (OP2 optInd orExpr)*
orExpr = andExpr (OP3 optInd andExpr)*
andExpr = cmpExpr (OP4 optInd cmpExpr)*
cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
sliceExpr = ampExpr (OP6 optInd ampExpr)*
ampExpr = plusExpr (OP7 optInd plusExpr)*
plusExpr = mulExpr (OP8 optInd mulExpr)*
mulExpr = dollarExpr (OP9 optInd dollarExpr)*
dollarExpr = primary (OP10 optInd primary)*
symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
       | IDENT | 'addr' | 'type'
indexExpr = expr
indexExprList = indexExpr ^+ comma
exprColonEqExpr = expr (':'|'=' expr)?
exprList = expr ^+ comma
dotExpr = expr '.' optInd symbol
qualifiedIdent = symbol ('.' optInd symbol)?
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
        | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
        | 'when' | 'var' | 'mixin'
par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
                 | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
                            | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
        optPar ')'
literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
          | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
          | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
          | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
          | CHAR_LIT
          | NIL
generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
identOrLiteral = generalizedLit | symbol | literal
               | par | arrayConstr | setOrTableConstr
               | castExpr
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
      | doBlocks
      | '.' optInd symbol generalizedLit?
      | '[' optInd indexExprList optPar ']'
      | '{' optInd indexExprList optPar '}'
      | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
condExpr = expr colcom expr optInd
        ('elif' expr colcom expr optInd)*
         'else' colcom expr
ifExpr = 'if' condExpr
whenExpr = 'when' condExpr
pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
identVis = symbol opr?  # postfix position
identWithPragma = identVis pragma?
declColonEquals = identWithPragma (comma identWithPragma)* comma?
                  (':' optInd typeDesc)? ('=' optInd expr)?
identColonEquals = ident (comma ident)* comma?
     (':' optInd typeDesc)? ('=' optInd expr)?)
inlTupleDecl = 'tuple'
    [' optInd  (identColonEquals (comma/semicolon)?)*  optPar ']'
extTupleDecl = 'tuple'
    COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
tupleClass = 'tuple'
paramList = '(' declColonEquals ^* (comma/semicolon) ')'
paramListArrow = paramList? ('->' optInd typeDesc)?
paramListColon = paramList? (':' optInd typeDesc)?
doBlock = 'do' paramListArrow pragmas? colcom stmt
doBlocks = doBlock ^* IND{=}
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
distinct = 'distinct' optInd typeDesc
expr = (ifExpr
      | whenExpr
      | caseExpr
      | tryExpr)
      / simpleExpr
typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'tuple'
         | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
primary = typeKeyw typeDescK
        /  prefixOperator* identOrLiteral primarySuffix*
        / 'static' primary
        / 'bind' primary
typeDesc = simpleExpr
typeDefAux = simpleExpr
           | 'concept' typeClass
macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
                       | IND{=} 'elif' expr ':' stmt
                       | IND{=} 'except' exprList ':' stmt
                       | IND{=} 'else' ':' stmt )*
exprStmt = simpleExpr
         (( '=' optInd expr )
         / ( expr ^+ comma
             doBlocks
              / macroColon
           ))?
importStmt = 'import' optInd expr
              ((comma expr)*
              / 'except' optInd (expr ^+ comma))
includeStmt = 'include' optInd expr ^+ comma
fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
returnStmt = 'return' optInd expr?
raiseStmt = 'raise' optInd expr?
yieldStmt = 'yield' optInd expr?
discardStmt = 'discard' optInd expr?
breakStmt = 'break' optInd expr?
continueStmt = 'break' optInd expr?
condStmt = expr colcom stmt COMMENT?
           (IND{=} 'elif' expr colcom stmt)*
           (IND{=} 'else' colcom stmt)?
ifStmt = 'if' condStmt
whenStmt = 'when' condStmt
whileStmt = 'while' expr colcom stmt
ofBranch = 'of' exprList colcom stmt
ofBranches = ofBranch (IND{=} ofBranch)*
                      (IND{=} 'elif' expr colcom stmt)*
                      (IND{=} 'else' colcom stmt)?
caseStmt = 'case' expr ':'? COMMENT?
            (IND{>} ofBranches DED
            | IND{=} ofBranches)
tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
           (IND{=}? 'except' exprList colcom stmt)*
           (IND{=}? 'finally' colcom stmt)?
tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
           (optInd 'except' exprList colcom stmt)*
           (optInd 'finally' colcom stmt)?
exceptBlock = 'except' colcom stmt
forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
blockStmt = 'block' symbol? colcom stmt
staticStmt = 'static' colcom stmt
deferStmt = 'defer' colcom stmt
asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
genericParamList = '[' optInd
  genericParam ^* (comma/semicolon) optPar ']'
pattern = '{' stmt '}'
indAndComment = (IND{>} COMMENT)? | COMMENT?
routine = optInd identVis pattern? genericParamList?
  paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
commentStmt = COMMENT
section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
objectWhen = 'when' expr colcom objectPart COMMENT?
            ('elif' expr colcom objectPart COMMENT?)*
            ('else' colcom objectPart COMMENT?)?
objectBranch = 'of' exprList colcom objectPart
objectBranches = objectBranch (IND{=} objectBranch)*
                      (IND{=} 'elif' expr colcom objectPart)*
                      (IND{=} 'else' colcom objectPart)?
objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
            (IND{>} objectBranches DED
            | IND{=} objectBranches)
objectPart = IND{>} objectPart^+IND{=} DED
           / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals
object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
typeClassParam = ('var')? symbol
typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
              &IND{>} stmt
typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
            indAndComment?
varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
variable = (varTuple / identColonEquals) indAndComment
bindStmt = 'bind' optInd qualifiedIdent ^+ comma
mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
pragmaStmt = pragma (':' COMMENT? stmt)?
simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
           | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
           | includeStmt | commentStmt) / exprStmt) COMMENT?
complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
                    | tryStmt | forStmt
                    | blockStmt | staticStmt | deferStmt | asmStmt
                    | 'proc' routine
                    | 'method' routine
                    | 'iterator' routine
                    | 'macro' routine
                    | 'template' routine
                    | 'converter' routine
                    | 'type' section(typeDef)
                    | 'const' section(constant)
                    | ('let' | 'var') section(variable)
                    | bindStmt | mixinStmt)
                    / simpleStmt
stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
     / simpleStmt ^+ ';'


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值