# # # The Nimrod Compiler # (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # This module implements the parser of the standard Nimrod syntax. # The parser strictly reflects the grammar ("doc/grammar.txt"); however # it uses several helper routines to keep the parser small. A special # efficient algorithm is used for the precedence levels. The parser here can # be seen as a refinement of the grammar, as it specifies how the AST is build # from the grammar and how comments belong to the AST. import llstream, lexer, idents, strutils, ast, msgs type TParser*{.final.} = object # a TParser object represents a module that # is being parsed lex*: TLexer # the lexer that is used for parsing tok*: TToken # the current token proc ParseAll*(p: var TParser): PNode proc openParser*(p: var TParser, filename: string, inputstream: PLLStream) proc closeParser*(p: var TParser) proc parseTopLevelStmt*(p: var TParser): PNode # implements an iterator. Returns the next top-level statement or # emtyNode if end of stream. # helpers for the other parsers proc getPrecedence*(tok: TToken): int proc isOperator*(tok: TToken): bool proc getTok*(p: var TParser) proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "") proc skipComment*(p: var TParser, node: PNode) proc newNodeP*(kind: TNodeKind, p: TParser): PNode proc newIntNodeP*(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode proc newStrNodeP*(kind: TNodeKind, strVal: string, p: TParser): PNode proc newIdentNodeP*(ident: PIdent, p: TParser): PNode proc expectIdentOrKeyw*(p: TParser) proc ExpectIdent*(p: TParser) proc parLineInfo*(p: TParser): TLineInfo proc Eat*(p: var TParser, TokType: TTokType) proc skipInd*(p: var TParser) proc optPar*(p: var TParser) proc optInd*(p: var TParser, n: PNode) proc indAndComment*(p: var TParser, n: PNode) proc setBaseFlags*(n: PNode, base: TNumericalBase) proc parseSymbol*(p: var TParser): PNode # implementation proc getTok(p: var TParser) = rawGetTok(p.lex, p.tok) proc OpenParser(p: var TParser, filename: string, inputStream: PLLStream) = initToken(p.tok) OpenLexer(p.lex, filename, inputstream) getTok(p) # read the first token proc CloseParser(p: var TParser) = CloseLexer(p.lex) proc parMessage(p: TParser, msg: TMsgKind, arg: string = "") = lexMessage(p.lex, msg, arg) proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) = lexMessage(p.lex, msg, prettyTok(tok)) proc skipComment(p: var TParser, node: PNode) = if p.tok.tokType == tkComment: if node != nil: if node.comment == nil: node.comment = "" add(node.comment, p.tok.literal) else: parMessage(p, errInternal, "skipComment") getTok(p) proc skipInd(p: var TParser) = if p.tok.tokType == tkInd: getTok(p) proc optPar(p: var TParser) = if p.tok.tokType == tkSad or p.tok.tokType == tkInd: getTok(p) proc optInd(p: var TParser, n: PNode) = skipComment(p, n) skipInd(p) proc expectIdentOrKeyw(p: TParser) = if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType): lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) proc ExpectIdent(p: TParser) = if p.tok.tokType != tkSymbol: lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) proc Eat(p: var TParser, TokType: TTokType) = if p.tok.TokType == TokType: getTok(p) else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType]) proc parLineInfo(p: TParser): TLineInfo = result = getLineInfo(p.lex) proc indAndComment(p: var TParser, n: PNode) = if p.tok.tokType == tkInd: var info = parLineInfo(p) getTok(p) if p.tok.tokType == tkComment: skipComment(p, n) else: LocalError(info, errInvalidIndentation) else: skipComment(p, n) proc newNodeP(kind: TNodeKind, p: TParser): PNode = result = newNodeI(kind, getLineInfo(p.lex)) proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = result = newNodeP(kind, p) result.intVal = intVal proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode = result = newNodeP(kind, p) result.floatVal = floatVal proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = result = newNodeP(kind, p) result.strVal = strVal proc newIdentNodeP(ident: PIdent, p: TParser): PNode = result = newNodeP(nkIdent, p) result.ident = ident proc parseExpr(p: var TParser): PNode proc parseStmt(p: var TParser): PNode proc parseTypeDesc(p: var TParser): PNode proc parseParamList(p: var TParser): PNode proc IsLeftAssociative(tok: TToken): bool {.inline.} = result = tok.tokType != tkOpr or tok.ident.s[0] != '^' proc getPrecedence(tok: TToken): int = case tok.tokType of tkOpr: case tok.ident.s[0] of '$', '^': result = 9 of '*', '%', '/', '\\': result = 8 of '+', '-', '~', '|': result = 7 of '&': result = 6 of '=', '<', '>', '!': result = 4 of '.': result = 5 else: result = 1 of tkDiv, tkMod, tkShl, tkShr: result = 8 of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf: result = 4 of tkDotDot: result = 5 of tkAnd: result = 3 of tkOr, tkXor: result = 2 else: result = - 10 proc isOperator(tok: TToken): bool = result = getPrecedence(tok) >= 0 proc parseSymbol(p: var TParser): PNode = case p.tok.tokType of tkSymbol: result = newIdentNodeP(p.tok.ident, p) getTok(p) of tkAccent: result = newNodeP(nkAccQuoted, p) getTok(p) while true: case p.tok.tokType of tkBracketLe: add(result, newIdentNodeP(getIdent"[]", p)) getTok(p) eat(p, tkBracketRi) of tkEquals: add(result, newIdentNodeP(getIdent"=", p)) getTok(p) of tkParLe: add(result, newIdentNodeP(getIdent"()", p)) getTok(p) eat(p, tkParRi) of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDotDot: add(result, newIdentNodeP(p.tok.ident, p)) getTok(p) of tkIntLit..tkCharLit: add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p)) getTok(p) else: if result.len == 0: parMessage(p, errIdentifierExpected, p.tok) break eat(p, tkAccent) else: parMessage(p, errIdentifierExpected, p.tok) getTok(p) # BUGFIX: We must consume a token here to prevent endless loops! result = ast.emptyNode proc indexExpr(p: var TParser): PNode = result = parseExpr(p) proc indexExprList(p: var TParser, first: PNode): PNode = result = newNodeP(nkBracketExpr, p) addSon(result, first) getTok(p) optInd(p, result) while (p.tok.tokType != tkBracketRi) and (p.tok.tokType != tkEof) and (p.tok.tokType != tkSad): var a = indexExpr(p) addSon(result, a) if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) optPar(p) eat(p, tkBracketRi) proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode = var a = parseExpr(p) if p.tok.tokType == tok: result = newNodeP(kind, p) getTok(p) #optInd(p, result) addSon(result, a) addSon(result, parseExpr(p)) else: result = a proc exprList(p: var TParser, endTok: TTokType, result: PNode) = getTok(p) optInd(p, result) while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): var a = parseExpr(p) addSon(result, a) if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) eat(p, endTok) proc qualifiedIdent(p: var TParser): PNode = result = parseSymbol(p) #optInd(p, result); if p.tok.tokType == tkDot: getTok(p) optInd(p, result) var a = result result = newNodeI(nkDotExpr, a.info) addSon(result, a) addSon(result, parseSymbol(p)) proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) = getTok(p) optInd(p, result) while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): var a = qualifiedIdent(p) addSon(result, a) #optInd(p, a); if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) eat(p, endTok) proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind, endTok, sepTok: TTokType, result: PNode) = assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) getTok(p) optInd(p, result) while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and (p.tok.tokType != tkSad) and (p.tok.tokType != tkInd): var a = exprColonEqExpr(p, elemKind, sepTok) addSon(result, a) if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) optPar(p) eat(p, endTok) proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind, endTok, sepTok: TTokType): PNode = result = newNodeP(kind, p) exprColonEqExprListAux(p, elemKind, endTok, sepTok, result) proc setOrTableConstr(p: var TParser): PNode = result = newNodeP(nkCurly, p) getTok(p) # skip '{' optInd(p, result) if p.tok.tokType == tkColon: getTok(p) # skip ':' result.kind = nkTableConstr else: while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}: var a = exprColonEqExpr(p, nkExprColonExpr, tkColon) if a.kind == nkExprColonExpr: result.kind = nkTableConstr addSon(result, a) if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) optPar(p) eat(p, tkCurlyRi) # skip '}' proc parseCast(p: var TParser): PNode = result = newNodeP(nkCast, p) getTok(p) eat(p, tkBracketLe) optInd(p, result) addSon(result, parseTypeDesc(p)) optPar(p) eat(p, tkBracketRi) eat(p, tkParLe) optInd(p, result) addSon(result, parseExpr(p)) optPar(p) eat(p, tkParRi) proc parseAddr(p: var TParser): PNode = result = newNodeP(nkAddr, p) getTok(p) eat(p, tkParLe) optInd(p, result) addSon(result, parseExpr(p)) optPar(p) eat(p, tkParRi) proc setBaseFlags(n: PNode, base: TNumericalBase) = case base of base10: nil of base2: incl(n.flags, nfBase2) of base8: incl(n.flags, nfBase8) of base16: incl(n.flags, nfBase16) proc parseGStrLit(p: var TParser, a: PNode): PNode = case p.tok.tokType of tkGStrLit: result = newNodeP(nkCallStrLit, p) addSon(result, a) addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) getTok(p) of tkGTripleStrLit: result = newNodeP(nkCallStrLit, p) addSon(result, a) addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)) getTok(p) else: result = a proc identOrLiteral(p: var TParser): PNode = case p.tok.tokType of tkSymbol: result = newIdentNodeP(p.tok.ident, p) getTok(p) result = parseGStrLit(p, result) of tkAccent: result = parseSymbol(p) # literals of tkIntLit: result = newIntNodeP(nkIntLit, p.tok.iNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkInt8Lit: result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkInt16Lit: result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkInt32Lit: result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkInt64Lit: result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkFloatLit: result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkFloat32Lit: result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkFloat64Lit: result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p) setBaseFlags(result, p.tok.base) getTok(p) of tkStrLit: result = newStrNodeP(nkStrLit, p.tok.literal, p) getTok(p) of tkRStrLit: result = newStrNodeP(nkRStrLit, p.tok.literal, p) getTok(p) of tkTripleStrLit: result = newStrNodeP(nkTripleStrLit, p.tok.literal, p) getTok(p) of tkCharLit: result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p) getTok(p) of tkNil: result = newNodeP(nkNilLit, p) getTok(p) of tkParLe: # () constructor result = exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, tkColon) of tkCurlyLe: # {} constructor result = setOrTableConstr(p) of tkBracketLe: # [] constructor result = exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi, tkColon) of tkCast: result = parseCast(p) of tkAddr: result = parseAddr(p) else: parMessage(p, errExprExpected, p.tok) getTok(p) # we must consume a token here to prevend endless loops! result = ast.emptyNode proc primary(p: var TParser): PNode = # prefix operator? if isOperator(p.tok): result = newNodeP(nkPrefix, p) var a = newIdentNodeP(p.tok.ident, p) addSon(result, a) getTok(p) optInd(p, a) addSon(result, primary(p)) return elif p.tok.tokType == tkBind: result = newNodeP(nkBind, p) getTok(p) optInd(p, result) addSon(result, primary(p)) return result = identOrLiteral(p) while true: case p.tok.tokType of tkParLe: var a = result result = newNodeP(nkCall, p) addSon(result, a) exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result) of tkDot: var a = result result = newNodeP(nkDotExpr, p) addSon(result, a) getTok(p) # skip '.' optInd(p, result) addSon(result, parseSymbol(p)) result = parseGStrLit(p, result) of tkBracketLe: result = indexExprList(p, result) else: break proc lowestExprAux(p: var TParser, limit: int): PNode = result = primary(p) # expand while operators have priorities higher than 'limit' var opPrec = getPrecedence(p.tok) while opPrec >= limit: var leftAssoc = ord(IsLeftAssociative(p.tok)) var a = newNodeP(nkInfix, p) var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: getTok(p) optInd(p, opNode) # read sub-expression with higher priority
# Nimrod wrapper of 0mq
# Generated by c2nim with modifications and enhancement from Andreas Rumpf
# Original licence follows:

#
#    Copyright (c) 2007-2011 iMatix Corporation
#    Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
#
#    This file is part of 0MQ.
#
#    0MQ is free software; you can redistribute it and/or modify it under
#    the terms of the GNU Lesser General Public License as published by
#    the Free Software Foundation; either version 3 of the License, or
#    (at your option) any later version.
#
#    0MQ is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# Generated from zmq version 2.1.5

## Nimrod 0mq wrapper. This file contains the low level C wrappers as well as
## some higher level constructs. The higher level constructs are easily
## recognizable because they are the only ones that have documentation.


{.deadCodeElim: on.}
when defined(windows): 
  const 
    zmqdll* = "zmq.dll"
elif defined(macosx): 
  const 
    zmqdll* = "libzmq.dylib"
else:
  const 
    zmqdll* = "libzmq.so"

# A number random enough not to collide with different errno ranges on      
# different OSes. The assumption is that error_t is at least 32-bit type.  
const 
  HAUSNUMERO* = 156384712
  # On Windows platform some of the standard POSIX errnos are not defined.    
  ENOTSUP* = (HAUSNUMERO + 1)
  EPROTONOSUPPORT* = (HAUSNUMERO + 2)
  ENOBUFS* = (HAUSNUMERO + 3)
  ENETDOWN* = (HAUSNUMERO + 4)
  EADDRINUSE* = (HAUSNUMERO + 5)
  EADDRNOTAVAIL* = (HAUSNUMERO + 6)
  ECONNREFUSED* = (HAUSNUMERO + 7)
  EINPROGRESS* = (HAUSNUMERO + 8)
  # Native 0MQ error codes.  
  EFSM* = (HAUSNUMERO + 51)
  ENOCOMPATPROTO* = (HAUSNUMERO + 52)
  ETERM* = (HAUSNUMERO + 53)
  EMTHREAD* = (HAUSNUMERO + 54)
  #  Maximal size of "Very Small Message". VSMs are passed by value            
  #  to avoid excessive memory allocation/deallocation.                        
  #  If VMSs larger than 255 bytes are required, type of 'vsm_size'            
  #  field in msg_t structure should be modified accordingly.
  MAX_VSM_SIZE* = 30

  POLLIN* = 1
  POLLOUT* = 2
  POLLERR* = 4

  STREAMER* = 1
  FORWARDER* = 2
  QUEUE* = 3

  PAIR* = 0
  PUB* = 1
  SUB* = 2
  REQ* = 3
  REP* = 4
  DEALER* = 5
  ROUTER* = 6
  PULL* = 7
  PUSH* = 8
  XPUB* = 9
  XSUB* = 10
  XREQ* = DEALER      #  Old alias, remove in 3.x               
  XREP* = ROUTER      #  Old alias, remove in 3.x               
  UPSTREAM* = PULL    #  Old alias, remove in 3.x               
  DOWNSTREAM* = PUSH  #  Old alias, remove in 3.x        

type
  #  Message types. These integers may be stored in 'content' member of the    
  #  message instead of regular pointer to the data. 
  TMsgTypes* = enum
    DELIMITER = 31,
    VSM = 32
  #  Message flags. MSG_SHARED is strictly speaking not a message flag     
  #  (it has no equivalent in the wire format), however, making  it a flag     
  #  allows us to pack the stucture tighter and thus improve performance.   
  TMsgFlags* = enum 
    MSG_MORE = 1,
    MSG_SHARED = 128,
    MSG_MASK = 129         # Merges all the flags 
  #  A message. Note that 'content' is not a pointer to the raw data.          
  #  Rather it is pointer to zmq::msg_content_t structure                      
  #  (see src/msg_content.hpp for its definition).    
  TMsg*{.pure, final.} = object 
    content*: pointer
    flags*: char
    vsm_size*: char
    vsm_data*: array[0..MAX_VSM_SIZE - 1, char]

  TFreeFn = proc (data, hint: pointer) {.noconv.}

  TContext {.final, pure.} = object
  PContext* = ptr TContext
  
  # Socket Types
  TSocket {.final, pure.} = object
  PSocket* = ptr TSocket       

  #  Socket options.                                                           
  TSockOptions* = enum
    HWM = 1,
    SWAP = 3,
    AFFINITY = 4,
    IDENTITY = 5,
    SUBSCRIBE = 6,
    UNSUBSCRIBE = 7,
    RATE = 8,
    RECOVERY_IVL = 9,
    MCAST_LOOP = 10,
    SNDBUF = 11,
    RCVBUF = 12,
    RCVMORE = 13,
    FD = 14,
    EVENTS = 15,
    theTYPE