diff options
author | Araq <rumpf_a@web.de> | 2013-09-10 00:40:06 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-09-10 00:40:06 +0200 |
commit | db19b1824197cb8051ab630bbc96ca51821f7f3b (patch) | |
tree | d06b626b382a55b919171575ca0fc06d18401274 /compiler/c2nim/cparse.nim | |
parent | 094d7fd4b1e4cd23450f0f5c7e1e2971dc2dcaa6 (diff) | |
download | Nim-db19b1824197cb8051ab630bbc96ca51821f7f3b.tar.gz |
cn2im: basic C++ support
Diffstat (limited to 'compiler/c2nim/cparse.nim')
-rw-r--r-- | compiler/c2nim/cparse.nim | 515 |
1 files changed, 462 insertions, 53 deletions
diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim index b964ed976..6bb4451e4 100644 --- a/compiler/c2nim/cparse.nim +++ b/compiler/c2nim/cparse.nim @@ -11,7 +11,11 @@ ## It translates a C source file into a Nimrod AST. Then the renderer can be ## used to convert the AST to its text representation. -# XXX cleanup of declaration handling. +# TODO +# - implement handling of '::' +# - C++'s "operator" still needs some love +# - ignore 'using' statements +# - support '#if' in classes import os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs, @@ -24,14 +28,17 @@ type pfStdCall, ## annotate procs with stdcall pfSkipInclude, ## skip all ``#include`` pfTypePrefixes, ## all generated types start with 'T' or 'P' - pfSkipComments ## do not generate comments + pfSkipComments, ## do not generate comments + pfCpp, ## process C++ + pfIgnoreRValueRefs, ## transform C++'s 'T&&' to 'T' + pfKeepBodies ## do not skip C++ method bodies - TMacro {.final.} = object + TMacro = object name: string params: int # number of parameters body: seq[ref TToken] # can contain pxMacroParam tokens - TParserOptions {.final.} = object + TParserOptions = object flags: set[TParserFlag] prefixes, suffixes: seq[string] mangleRules: seq[tuple[pattern: TPeg, frmt: string]] @@ -41,7 +48,7 @@ type toMangle: PStringTable PParserOptions* = ref TParserOptions - TParser* {.final.} = object + TParser* = object lex: TLexer tok: ref TToken # current token options: PParserOptions @@ -49,6 +56,7 @@ type inTypeDef: int scopeCounter: int hasDeadCodeElimPragma: bool + currentClass: PNode # type that needs to be added as 'this' parameter TReplaceTuple* = array[0..1, string] @@ -66,7 +74,7 @@ proc newParserOptions*(): PParserOptions = proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool = result = true - case key + case key.normalize of "ref": incl(parserOptions.flags, pfRefs) of "dynlib": parserOptions.dynlibSym = val of "header": parserOptions.header = val @@ -77,6 +85,9 @@ proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool = of "skipinclude": incl(parserOptions.flags, pfSkipInclude) of "typeprefixes": incl(parserOptions.flags, pfTypePrefixes) of "skipcomments": incl(parserOptions.flags, pfSkipComments) + of "cpp": incl(parserOptions.flags, pfCpp) + of "keepbodies": incl(parserOptions.flags, pfKeepBodies) + of "ignorervaluerefs": incl(parserOptions.flags, pfIgnoreRValueRefs) else: result = false proc ParseUnit*(p: var TParser): PNode @@ -94,6 +105,7 @@ proc OpenParser(p: var TParser, filename: string, new(p.tok) proc parMessage(p: TParser, msg: TMsgKind, arg = "") = + #assert false lexMessage(p.lex, msg, arg) proc CloseParser(p: var TParser) = CloseLexer(p.lex) @@ -116,6 +128,13 @@ proc rawGetTok(p: var TParser) = p.tok.next = t p.tok = t +proc insertAngleRi(currentToken: ref TToken) = + var t: ref TToken + new(t) + t.xkind = pxAngleRi + t.next = currentToken.next + currentToken.next = t + proc findMacro(p: TParser): int = for i in 0..high(p.options.macros): if p.tok.s == p.options.macros[i].name: return i @@ -346,6 +365,14 @@ proc DoImport(ident: string, pragmas: PNode, p: TParser) = if p.options.dynlibSym.len > 0 or p.options.header.len > 0: addImportToPragma(pragmas, ident, p) +proc DoImportCpp(ident: string, pragmas: PNode, p: TParser) = + if p.options.dynlibSym.len > 0 or p.options.header.len > 0: + addSon(pragmas, newIdentStrLitPair("importcpp", ident, p)) + if p.options.dynlibSym.len > 0: + addSon(pragmas, newIdentPair("dynlib", p.options.dynlibSym, p)) + else: + addSon(pragmas, newIdentStrLitPair("header", p.options.header, p)) + proc newBinary(opr: string, a, b: PNode, p: TParser): PNode = result = newNodeP(nkInfix, p) addSon(result, newIdentNodeP(getIdent(opr), p)) @@ -396,7 +423,7 @@ proc assignmentExpression(p: var TParser): PNode proc compoundStatement(p: var TParser): PNode proc statement(p: var TParser): PNode -proc declKeyword(s: string): bool = +proc declKeyword(p: TParser, s: string): bool = # returns true if it is a keyword that introduces a declaration case s of "extern", "static", "auto", "register", "const", "volatile", "restrict", @@ -404,6 +431,8 @@ proc declKeyword(s: string): bool = "__safecall", "void", "struct", "union", "enum", "typedef", "short", "int", "long", "float", "double", "signed", "unsigned", "char": result = true + of "class": + result = p.options.flags.contains(pfCpp) proc stmtKeyword(s: string): bool = case s @@ -423,6 +452,59 @@ proc skipConst(p: var TParser) = (p.tok.s == "const" or p.tok.s == "volatile" or p.tok.s == "restrict"): getTok(p, nil) +proc isTemplateAngleBracket(p: var TParser): bool = + if pfCpp notin p.options.flags: return false + saveContext(p) + getTok(p, nil) # skip "<" + var i: array[pxParLe..pxCurlyLe, int] + var angles = 0 + while true: + let kind = p.tok.xkind + case kind + of pxEof: break + of pxParLe, pxBracketLe, pxCurlyLe: inc(i[kind]) + of pxGt, pxAngleRi: + # end of arguments? + if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0 and + angles == 0: + # mark as end token: + p.tok.xkind = pxAngleRi + result = true; + break + if angles > 0: dec(angles) + of pxShr: + # >> can end a template too: + if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0 and + angles == 1: + p.tok.xkind = pxAngleRi + insertAngleRi(p.tok) + result = true + break + if angles > 1: dec(angles, 2) + of pxLt: inc(angles) + of pxParRi, pxBracketRi, pxCurlyRi: + let kind = pred(kind, 3) + if i[kind] > 0: dec(i[kind]) + else: break + of pxSemicolon: break + else: discard + getTok(p, nil) + backtrackContext(p) + +proc optAngle(p: var TParser, n: PNode): PNode = + if p.tok.xkind == pxLt and isTemplateAngleBracket(p): + getTok(p) + result = newNodeP(nkBracketExpr, p) + result.add(n) + while true: + let a = assignmentExpression(p) + if not a.isNil: result.add(a) + if p.tok.xkind != pxComma: break + getTok(p) + eat(p, pxAngleRi) + else: + result = n + proc typeAtom(p: var TParser): PNode = skipConst(p) ExpectIdent(p) @@ -451,6 +533,7 @@ proc typeAtom(p: var TParser): PNode = else: result = mangledIdent(p.tok.s, p) getTok(p, result) + result = optAngle(p, result) proc newPointerTy(p: TParser, typ: PNode): PNode = if pfRefs in p.options.flags: @@ -458,16 +541,31 @@ proc newPointerTy(p: TParser, typ: PNode): PNode = else: result = newNodeP(nkPtrTy, p) result.addSon(typ) - + proc pointer(p: var TParser, a: PNode): PNode = result = a var i = 0 skipConst(p) - while p.tok.xkind == pxStar: - inc(i) - getTok(p, result) - skipConst(p) - result = newPointerTy(p, result) + while true: + if p.tok.xkind == pxStar: + inc(i) + getTok(p, result) + skipConst(p) + result = newPointerTy(p, result) + elif p.tok.xkind == pxAmp and pfCpp in p.options.flags: + getTok(p, result) + skipConst(p) + let b = result + result = newNodeP(nkVarTy, p) + result.add(b) + elif p.tok.xkind == pxAmpAmp and pfCpp in p.options.flags: + getTok(p, result) + skipConst(p) + if pfIgnoreRvalueRefs notin p.options.flags: + let b = result + result = newNodeP(nkVarTy, p) + result.add(b) + else: break if a.kind == nkIdent and a.ident.s == "char": if i >= 2: result = newIdentNodeP("cstringArray", p) @@ -553,9 +651,9 @@ proc takeOnlyFirstField(p: TParser, isUnion: bool): bool = # if we generate an interface to a header file, *all* fields can be # generated: result = isUnion and p.options.header.len == 0 - + proc parseStructBody(p: var TParser, isUnion: bool, - kind: TNodeKind = nkRecList): PNode = + kind: TNodeKind = nkRecList): PNode = result = newNodeP(kind, p) eat(p, pxCurlyLe, result) while p.tok.xkind notin {pxEof, pxCurlyRi}: @@ -682,7 +780,7 @@ proc addTypeDef(section, name, t: PNode) = proc otherTypeDef(p: var TParser, section, typ: PNode) = var name: PNode var t = typ - if p.tok.xkind == pxStar: + if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp}: t = pointer(p, t) if p.tok.xkind == pxParLe: # function pointer: typedef typ (*name)(); @@ -819,6 +917,12 @@ proc parseTypeDef(p: var TParser): PNode = of "struct": parseTypedefStruct(p, result, isUnion=false) of "union": parseTypedefStruct(p, result, isUnion=true) of "enum": parseTypedefEnum(p, result) + of "class": + if pfCpp in p.options.flags: + parseTypedefStruct(p, result, isUnion=false) + else: + var t = typeAtom(p) + otherTypeDef(p, result, t) else: var t = typeAtom(p) otherTypeDef(p, result, t) @@ -871,22 +975,16 @@ proc parseVarDecl(p: var TParser, baseTyp, typ: PNode, addSon(result, def) eat(p, pxSemicolon) -when false: - proc declaration(p: var TParser, father: PNode) = - # general syntax to parse is:: - # - # baseType ::= typeIdent | ((struct|union|enum) ident ("{" body "}" )? - # | "{" body "}") - # declIdent ::= "(" "*" ident ")" formalParams ("=" exprNoComma)? - # | ident ((formalParams ("{" statements "}")?)|"=" - # exprNoComma|(typeSuffix("=" exprNoComma)? ))? - # declaration ::= baseType (pointers)? declIdent ("," declIdent)* - var pragmas = newNodeP(nkPragma, p) - - skipDeclarationSpecifiers(p) - parseCallConv(p, pragmas) - skipDeclarationSpecifiers(p) - expectIdent(p) +proc declarationName(p: var TParser): string = + expectIdent(p) + result = p.tok.s + getTok(p) # skip identifier + while p.tok.xkind == pxScope and pfCpp in p.options.flags: + getTok(p) # skip "::" + expectIdent(p) + result.add("::") + result.add(p.tok.s) + getTok(p) proc declaration(p: var TParser): PNode = result = newNodeP(nkProcDef, p) @@ -908,17 +1006,17 @@ proc declaration(p: var TParser): PNode = result = parseFunctionPointerDecl(p, rettyp) eat(p, pxSemicolon) return - ExpectIdent(p) - var origName = p.tok.s - getTok(p) # skip identifier - case p.tok.xkind - of pxParLe: + var origName = declarationName(p) + case p.tok.xkind + of pxParLe: # really a function! var name = mangledIdent(origName, p) var params = newNodeP(nkFormalParams, p) addReturnType(params, rettyp) parseFormalParams(p, params, pragmas) - + if pfCpp in p.options.flags and p.tok.xkind == pxSymbol and + p.tok.s == "const": + addSon(pragmas, newIdentNodeP("noSideEffect", p)) if pfCDecl in p.options.flags: addSon(pragmas, newIdentNodeP("cdecl", p)) elif pfStdcall in p.options.flags: @@ -1027,10 +1125,10 @@ proc isDefinitelyAType(p: var TParser): bool = while true: case p.tok.xkind of pxSymbol: - if declKeyword(p.tok.s): return true + if declKeyword(p, p.tok.s): return true elif starFound: return false else: inc(words) - of pxStar: + of pxStar, pxAmp, pxAmpAmp: starFound = true of pxParRi: return words == 0 or words > 1 or starFound else: return false @@ -1205,6 +1303,10 @@ proc postfixExpression(p: var TParser): PNode = addSon(result, newIdentNodeP("dec", p)) gettok(p, result) addSon(result, a) + of pxLt: + if isTemplateAngleBracket(p): + result = optAngle(p, result) + else: break else: break proc unaryExpression(p: var TParser): PNode = @@ -1222,9 +1324,24 @@ proc unaryExpression(p: var TParser): PNode = result = newNodeP(nkCall, p) addSon(result, newIdentNodeP("sizeof", p)) getTok(p, result) - if p.tok.xkind == pxParLe: + if p.tok.xkind == pxParLe: getTok(p, result) - addson(result, typeDesc(p)) + addSon(result, typeDesc(p)) + eat(p, pxParRi, result) + else: + addSon(result, unaryExpression(p)) + elif p.tok.s == "new" or p.tok.s == "delete" and pfCpp in p.options.flags: + var opr = p.tok.s + result = newNodeP(nkCall, p) + getTok(p, result) + if p.tok.xkind == pxBracketLe: + getTok(p) + eat(p, pxBracketRi) + opr.add("Array") + addSon(result, newIdentNodeP(opr, p)) + if p.tok.xkind == pxParLe: + getTok(p, result) + addSon(result, typeDesc(p)) eat(p, pxParRi, result) else: addSon(result, unaryExpression(p)) @@ -1455,14 +1572,14 @@ proc parseDoWhile(p: var TParser): PNode = proc declarationOrStatement(p: var TParser): PNode = if p.tok.xkind != pxSymbol: result = expressionStatement(p) - elif declKeyword(p.tok.s): + elif declKeyword(p, p.tok.s): result = declaration(p) else: # ordinary identifier: saveContext(p) getTok(p) # skip identifier to look ahead - case p.tok.xkind - of pxSymbol, pxStar: + case p.tok.xkind + of pxSymbol, pxStar, pxLt, pxAmp, pxAmpAmp: # we parse # a b # a * b @@ -1500,7 +1617,7 @@ proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) = if sonsLen(varSection) > 0: addSon(result, varSection) -proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode = +proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode = result = newNodeP(nkStmtList, p) saveContext(p) getTok(p, result) # skip "struct" or "union" @@ -1630,11 +1747,288 @@ proc compoundStatement(p: var TParser): PNode = if a.kind == nkEmpty: break embedStmts(result, a) if sonsLen(result) == 0: - # translate ``{}`` to Nimrod's ``nil`` statement - result = newNodeP(nkNilLit, p) + # translate ``{}`` to Nimrod's ``discard`` statement + result = newNodeP(nkDiscardStmt, p) + result.add(ast.emptyNode) dec(p.scopeCounter) eat(p, pxCurlyRi) +proc skipInheritKeyw(p: var TParser) = + if p.tok.xkind == pxSymbol and (p.tok.s == "private" or + p.tok.s == "protected" or + p.tok.s == "public"): + getTok(p) + +proc parseConstructor(p: var TParser, pragmas: PNode, + isDestructor=false): PNode = + var origName = p.tok.s + getTok(p) + + result = newNodeP(nkProcDef, p) + var rettyp = if isDestructor: newNodeP(nkNilLit, p) + else: mangledIdent(origName, p) + + let oname = if isDestructor: "destroy" & origName + else: "construct" & origName + var name = mangledIdent(oname, p) + var params = newNodeP(nkFormalParams, p) + addReturnType(params, rettyp) + if p.tok.xkind == pxParLe: + parseFormalParams(p, params, pragmas) + if p.tok.xkind == pxSymbol and p.tok.s == "const": + addSon(pragmas, newIdentNodeP("noSideEffect", p)) + if pfCDecl in p.options.flags: + addSon(pragmas, newIdentNodeP("cdecl", p)) + elif pfStdcall in p.options.flags: + addSon(pragmas, newIdentNodeP("stdcall", p)) + if p.tok.xkind == pxColon: + # skip initializer list: + while true: + getTok(p) + discard expression(p) + if p.tok.xkind != pxComma: break + # no pattern, no exceptions: + addSon(result, exportSym(p, name, origName), ast.emptyNode, ast.emptyNode) + addSon(result, params, pragmas, ast.emptyNode) # no exceptions + addSon(result, ast.emptyNode) # no body + case p.tok.xkind + of pxSemicolon: getTok(p) + of pxCurlyLe: + let body = compoundStatement(p) + if pfKeepBodies in p.options.flags: + result.sons[bodyPos] = body + else: + parMessage(p, errTokenExpected, ";") + if result.sons[bodyPos].kind == nkEmpty: + DoImport((if isDestructor: "~" else: "") & origName, pragmas, p) + elif isDestructor: + addSon(pragmas, newIdentNodeP("destructor", p)) + if sonsLen(result.sons[pragmasPos]) == 0: + result.sons[pragmasPos] = ast.emptyNode + +proc parseMethod(p: var TParser, origName: string, rettyp, pragmas: PNode, + isStatic: bool): PNode = + result = newNodeP(nkProcDef, p) + var params = newNodeP(nkFormalParams, p) + addReturnType(params, rettyp) + var thisDef = newNodeP(nkIdentDefs, p) + if not isStatic: + # declare 'this': + var t = newNodeP(nkVarTy, p) + t.add(p.currentClass) + addSon(thisDef, newIdentNodeP("this", p), t, ast.emptyNode) + params.add(thisDef) + parseFormalParams(p, params, pragmas) + if p.tok.xkind == pxSymbol and p.tok.s == "const": + addSon(pragmas, newIdentNodeP("noSideEffect", p)) + getTok(p, result) + if not isStatic: + # fix the type of the 'this' parameter: + thisDef.sons[1] = thisDef.sons[1].sons[0] + if pfCDecl in p.options.flags: + addSon(pragmas, newIdentNodeP("cdecl", p)) + elif pfStdcall in p.options.flags: + addSon(pragmas, newIdentNodeP("stdcall", p)) + # no pattern, no exceptions: + let methodName = newIdentNodeP(origName, p) + addSon(result, exportSym(p, methodName, origName), + ast.emptyNode, ast.emptyNode) + addSon(result, params, pragmas, ast.emptyNode) # no exceptions + addSon(result, ast.emptyNode) # no body + case p.tok.xkind + of pxSemicolon: getTok(p) + of pxCurlyLe: + let body = compoundStatement(p) + if pfKeepBodies in p.options.flags: + result.sons[bodyPos] = body + else: + parMessage(p, errTokenExpected, ";") + if result.sons[bodyPos].kind == nkEmpty: + if isStatic: DoImport(origName, pragmas, p) + else: DoImportCpp(origName, pragmas, p) + if sonsLen(result.sons[pragmasPos]) == 0: + result.sons[pragmasPos] = ast.emptyNode + +proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode + +proc followedByParLe(p: var TParser): bool = + saveContext(p) + getTok(p) # skip Identifier + result = p.tok.xkind == pxParLe + backtrackContext(p) + +proc parseOperator(p: var TParser, origName: var string): bool = + getTok(p) # skip 'operator' keyword + case p.tok.xkind + of pxAmp..pxArrow: + # ordinary operator symbol: + origName.add(TokKindToStr(p.tok.xkind)) + getTok(p) + of pxSymbol: + if p.tok.s == "new" or p.tok.s == "delete": + origName.add(p.tok.s) + getTok(p) + if p.tok.xkind == pxBracketLe: + getTok(p) + eat(p, pxBracketRi) + origName.add("[]") + else: + # type converter + let x = typeAtom(p) + if x.kind == nkIdent: + origName.add(x.ident.s) + else: + parMessage(p, errGenerated, "operator symbol expected") + result = true + of pxParLe: + getTok(p) + eat(p, pxParRi) + origName.add("()") + of pxBracketLe: + getTok(p) + eat(p, pxBracketRi) + origName.add("[]") + else: + parMessage(p, errGenerated, "operator symbol expected") + +proc parseClass(p: var TParser; isStruct: bool; stmtList: PNode): PNode = + result = newNodeP(nkObjectTy, p) + addSon(result, ast.emptyNode, ast.emptyNode) # no pragmas, no inheritance + + var recList = newNodeP(nkRecList, p) + addSon(result, recList) + if p.tok.xkind == pxColon: + getTok(p, result) + skipInheritKeyw(p) + var baseTyp = typeAtom(p) + var inh = newNodeP(nkOfInherit, p) + inh.add(baseTyp) + if p.tok.xkind == pxComma: + parMessage(p, errGenerated, "multiple inheritance is not supported") + while p.tok.xkind == pxComma: + getTok(p) + skipInheritKeyw(p) + discard typeAtom(p) + result.sons[0] = inh + + eat(p, pxCurlyLe, result) + var private = not isStruct + var pragmas = newNodeP(nkPragma, p) + while p.tok.xkind notin {pxEof, pxCurlyRi}: + skipCom(p, stmtList) + if p.tok.xkind == pxSymbol and (p.tok.s == "private" or + p.tok.s == "protected"): + getTok(p, result) + eat(p, pxColon, result) + private = true + elif p.tok.xkind == pxSymbol and p.tok.s == "public": + getTok(p, result) + eat(p, pxColon, result) + private = false + if p.tok.xkind == pxSymbol and p.tok.s == "friend": + # we skip friend declarations: + while p.tok.xkind notin {pxEof, pxSemicolon}: getTok(p) + eat(p, pxSemicolon) + elif p.tok.xkind == pxSymbol and p.tok.s == "enum": + let x = enumSpecifier(p) + if not private or pfKeepBodies in p.options.flags: stmtList.add(x) + elif p.tok.xkind == pxSymbol and p.tok.s == "typedef": + let x = parseTypeDef(p) + if not private or pfKeepBodies in p.options.flags: stmtList.add(x) + elif p.tok.xkind == pxSymbol and(p.tok.s == "struct" or p.tok.s == "class"): + let x = parseStandaloneClass(p, isStruct=p.tok.s == "struct") + if not private or pfKeepBodies in p.options.flags: stmtList.add(x) + elif p.tok.xkind == pxSymbol and p.tok.s == "union": + let x = parseStandaloneStruct(p, isUnion=true) + if not private or pfKeepBodies in p.options.flags: stmtList.add(x) + else: + if pragmas.len != 0: pragmas = newNodeP(nkPragma, p) + parseCallConv(p, pragmas) + var isStatic = false + if p.tok.xkind == pxSymbol and p.tok.s == "virtual": + getTok(p, stmtList) + if p.tok.xkind == pxSymbol and p.tok.s == "explicit": + getTok(p, stmtList) + if p.tok.xkind == pxSymbol and p.tok.s == "static": + getTok(p, stmtList) + isStatic = true + parseCallConv(p, pragmas) + if p.tok.xkind == pxSymbol and p.tok.s == p.currentClass.ident.s and + followedByParLe(p): + # constructor + let cons = parseConstructor(p, pragmas) + if not private or pfKeepBodies in p.options.flags: stmtList.add(cons) + elif p.tok.xkind == pxTilde: + # destructor + getTok(p, stmtList) + if p.tok.xkind == pxSymbol and p.tok.s == p.currentClass.ident.s: + let des = parseConstructor(p, pragmas, isDestructor=true) + if not private or pfKeepBodies in p.options.flags: stmtList.add(des) + else: + parMessage(p, errGenerated, "invalid destructor") + else: + # field declaration or method: + var baseTyp = typeAtom(p) + while true: + var def = newNodeP(nkIdentDefs, p) + var t = pointer(p, baseTyp) + let canBeMethod = p.tok.xkind != pxParLe + var origName: string + if p.tok.xkind == pxSymbol: + origName = p.tok.s + if p.tok.s == "operator": + var isConverter = parseOperator(p, origName) + let meth = parseMethod(p, origName, t, pragmas, isStatic) + if not private or pfKeepBodies in p.options.flags: + if isConverter: meth.kind = nkConverterDef + stmtList.add(meth) + break + var i = parseField(p, nkRecList) + if canBeMethod and p.tok.xkind == pxParLe: + let meth = parseMethod(p, origName, t, pragmas, isStatic) + if not private or pfKeepBodies in p.options.flags: + stmtList.add(meth) + else: + t = parseTypeSuffix(p, t) + addSon(def, i, t, ast.emptyNode) + if not isStatic: addSon(recList, def) + if p.tok.xkind != pxComma: break + getTok(p, def) + if p.tok.xkind == pxSemicolon: + getTok(p, lastSon(recList)) + eat(p, pxCurlyRi, result) + +proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode = + result = newNodeP(nkStmtList, p) + saveContext(p) + getTok(p, result) # skip "class" or "struct" + var origName = "" + let oldClass = p.currentClass + if p.tok.xkind == pxSymbol: + markTypeIdent(p, nil) + origName = p.tok.s + getTok(p, result) + p.currentClass = mangledIdent(origName, p) + else: + p.currentClass = nil + if p.tok.xkind in {pxCurlyLe, pxSemiColon, pxColon}: + if origName.len > 0: + var typeSection = newNodeP(nkTypeSection, p) + addSon(result, typeSection) + + var name = mangledIdent(origName, p) + var t = parseClass(p, isStruct, result) + addTypeDef(typeSection, structPragmas(p, name, origName), t) + parseTrailingDefinedIdents(p, result, name) + else: + var t = parseTuple(p, isUnion=false) + parseTrailingDefinedIdents(p, result, t) + else: + backtrackContext(p) + result = declaration(p) + p.currentClass = oldClass + + include cpp proc statement(p: var TParser): PNode = @@ -1681,14 +2075,29 @@ proc statement(p: var TParser): PNode = eat(p, pxSemicolon) of "enum": result = enumSpecifier(p) of "typedef": result = parseTypeDef(p) - of "struct": result = parseStandaloneStruct(p, isUnion=false) - of "union": result = parseStandaloneStruct(p, isUnion=true) + of "union": result = parseStandaloneStruct(p, isUnion=true) + of "struct": + if pfCpp in p.options.flags: + result = parseStandaloneClass(p, isStruct=true) + else: + result = parseStandaloneStruct(p, isUnion=false) + of "class": + if pfCpp in p.options.flags: + result = parseStandaloneClass(p, isStruct=false) + else: + result = declarationOrStatement(p) + of "namespace": + if pfCpp in p.options.flags: + while p.tok.xkind notin {pxEof, pxCurlyLe}: getTok(p) + result = compoundStatement(p) + else: + result = declarationOrStatement(p) else: result = declarationOrStatement(p) of pxCurlyLe: result = compoundStatement(p) of pxDirective, pxDirectiveParLe: result = parseDir(p) - of pxLineComment, pxStarComment: + of pxLineComment, pxStarComment: result = newNodeP(nkCommentStmt, p) skipCom(p, result) of pxSemicolon: @@ -1703,10 +2112,10 @@ proc statement(p: var TParser): PNode = result = expressionStatement(p) assert result != nil -proc parseUnit(p: var TParser): PNode = +proc parseUnit(p: var TParser): PNode = result = newNodeP(nkStmtList, p) getTok(p) # read first token - while p.tok.xkind != pxEof: + while p.tok.xkind != pxEof: var s = statement(p) if s.kind != nkEmpty: embedStmts(result, s) |