cn2im: basic C++ support
This commit is contained in:
parent
094d7fd4b1
commit
db19b18241
8 changed files with 720 additions and 55 deletions
|
|
@ -19,6 +19,7 @@ c2nim - C to Nimrod source converter
|
||||||
Usage: c2nim [options] inputfile [options]
|
Usage: c2nim [options] inputfile [options]
|
||||||
Options:
|
Options:
|
||||||
-o, --out:FILE set output filename
|
-o, --out:FILE set output filename
|
||||||
|
--cpp process C++ input file
|
||||||
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
||||||
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
||||||
--cdecl annotate procs with ``{.cdecl.}``
|
--cdecl annotate procs with ``{.cdecl.}``
|
||||||
|
|
@ -31,6 +32,8 @@ Options:
|
||||||
--skipinclude do not convert ``#include`` to ``import``
|
--skipinclude do not convert ``#include`` to ``import``
|
||||||
--typeprefixes generate ``T`` and ``P`` type prefixes
|
--typeprefixes generate ``T`` and ``P`` type prefixes
|
||||||
--skipcomments do not copy comments
|
--skipcomments do not copy comments
|
||||||
|
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
|
||||||
|
--keepBodies keep C++'s method bodies
|
||||||
-v, --version write c2nim's version
|
-v, --version write c2nim's version
|
||||||
-h, --help show this help
|
-h, --help show this help
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@ type
|
||||||
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
|
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
|
||||||
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
|
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
|
||||||
pxComma, pxSemiColon, pxColon,
|
pxComma, pxSemiColon, pxColon,
|
||||||
|
pxAngleRi # '>' but determined to be the end of a
|
||||||
|
# template's angle bracket
|
||||||
TTokKinds* = set[TTokKind]
|
TTokKinds* = set[TTokKind]
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -202,6 +204,7 @@ proc TokKindToStr*(k: TTokKind): string =
|
||||||
of pxColon: result = ":"
|
of pxColon: result = ":"
|
||||||
of pxCurlyLe: result = "{"
|
of pxCurlyLe: result = "{"
|
||||||
of pxCurlyRi: result = "}"
|
of pxCurlyRi: result = "}"
|
||||||
|
of pxAngleRi: result = "> [end of template]"
|
||||||
|
|
||||||
proc `$`(tok: TToken): string =
|
proc `$`(tok: TToken): string =
|
||||||
case tok.xkind
|
case tok.xkind
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@
|
||||||
## It translates a C source file into a Nimrod AST. Then the renderer can be
|
## It translates a C source file into a Nimrod AST. Then the renderer can be
|
||||||
## used to convert the AST to its text representation.
|
## 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
|
import
|
||||||
os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
|
os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
|
||||||
|
|
@ -24,14 +28,17 @@ type
|
||||||
pfStdCall, ## annotate procs with stdcall
|
pfStdCall, ## annotate procs with stdcall
|
||||||
pfSkipInclude, ## skip all ``#include``
|
pfSkipInclude, ## skip all ``#include``
|
||||||
pfTypePrefixes, ## all generated types start with 'T' or 'P'
|
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
|
name: string
|
||||||
params: int # number of parameters
|
params: int # number of parameters
|
||||||
body: seq[ref TToken] # can contain pxMacroParam tokens
|
body: seq[ref TToken] # can contain pxMacroParam tokens
|
||||||
|
|
||||||
TParserOptions {.final.} = object
|
TParserOptions = object
|
||||||
flags: set[TParserFlag]
|
flags: set[TParserFlag]
|
||||||
prefixes, suffixes: seq[string]
|
prefixes, suffixes: seq[string]
|
||||||
mangleRules: seq[tuple[pattern: TPeg, frmt: string]]
|
mangleRules: seq[tuple[pattern: TPeg, frmt: string]]
|
||||||
|
|
@ -41,7 +48,7 @@ type
|
||||||
toMangle: PStringTable
|
toMangle: PStringTable
|
||||||
PParserOptions* = ref TParserOptions
|
PParserOptions* = ref TParserOptions
|
||||||
|
|
||||||
TParser* {.final.} = object
|
TParser* = object
|
||||||
lex: TLexer
|
lex: TLexer
|
||||||
tok: ref TToken # current token
|
tok: ref TToken # current token
|
||||||
options: PParserOptions
|
options: PParserOptions
|
||||||
|
|
@ -49,6 +56,7 @@ type
|
||||||
inTypeDef: int
|
inTypeDef: int
|
||||||
scopeCounter: int
|
scopeCounter: int
|
||||||
hasDeadCodeElimPragma: bool
|
hasDeadCodeElimPragma: bool
|
||||||
|
currentClass: PNode # type that needs to be added as 'this' parameter
|
||||||
|
|
||||||
TReplaceTuple* = array[0..1, string]
|
TReplaceTuple* = array[0..1, string]
|
||||||
|
|
||||||
|
|
@ -66,7 +74,7 @@ proc newParserOptions*(): PParserOptions =
|
||||||
|
|
||||||
proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool =
|
proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool =
|
||||||
result = true
|
result = true
|
||||||
case key
|
case key.normalize
|
||||||
of "ref": incl(parserOptions.flags, pfRefs)
|
of "ref": incl(parserOptions.flags, pfRefs)
|
||||||
of "dynlib": parserOptions.dynlibSym = val
|
of "dynlib": parserOptions.dynlibSym = val
|
||||||
of "header": parserOptions.header = 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 "skipinclude": incl(parserOptions.flags, pfSkipInclude)
|
||||||
of "typeprefixes": incl(parserOptions.flags, pfTypePrefixes)
|
of "typeprefixes": incl(parserOptions.flags, pfTypePrefixes)
|
||||||
of "skipcomments": incl(parserOptions.flags, pfSkipComments)
|
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
|
else: result = false
|
||||||
|
|
||||||
proc ParseUnit*(p: var TParser): PNode
|
proc ParseUnit*(p: var TParser): PNode
|
||||||
|
|
@ -94,6 +105,7 @@ proc OpenParser(p: var TParser, filename: string,
|
||||||
new(p.tok)
|
new(p.tok)
|
||||||
|
|
||||||
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
|
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
|
||||||
|
#assert false
|
||||||
lexMessage(p.lex, msg, arg)
|
lexMessage(p.lex, msg, arg)
|
||||||
|
|
||||||
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
|
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
|
||||||
|
|
@ -116,6 +128,13 @@ proc rawGetTok(p: var TParser) =
|
||||||
p.tok.next = t
|
p.tok.next = t
|
||||||
p.tok = 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 =
|
proc findMacro(p: TParser): int =
|
||||||
for i in 0..high(p.options.macros):
|
for i in 0..high(p.options.macros):
|
||||||
if p.tok.s == p.options.macros[i].name: return i
|
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:
|
if p.options.dynlibSym.len > 0 or p.options.header.len > 0:
|
||||||
addImportToPragma(pragmas, ident, p)
|
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 =
|
proc newBinary(opr: string, a, b: PNode, p: TParser): PNode =
|
||||||
result = newNodeP(nkInfix, p)
|
result = newNodeP(nkInfix, p)
|
||||||
addSon(result, newIdentNodeP(getIdent(opr), p))
|
addSon(result, newIdentNodeP(getIdent(opr), p))
|
||||||
|
|
@ -396,7 +423,7 @@ proc assignmentExpression(p: var TParser): PNode
|
||||||
proc compoundStatement(p: var TParser): PNode
|
proc compoundStatement(p: var TParser): PNode
|
||||||
proc statement(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
|
# returns true if it is a keyword that introduces a declaration
|
||||||
case s
|
case s
|
||||||
of "extern", "static", "auto", "register", "const", "volatile", "restrict",
|
of "extern", "static", "auto", "register", "const", "volatile", "restrict",
|
||||||
|
|
@ -404,6 +431,8 @@ proc declKeyword(s: string): bool =
|
||||||
"__safecall", "void", "struct", "union", "enum", "typedef",
|
"__safecall", "void", "struct", "union", "enum", "typedef",
|
||||||
"short", "int", "long", "float", "double", "signed", "unsigned", "char":
|
"short", "int", "long", "float", "double", "signed", "unsigned", "char":
|
||||||
result = true
|
result = true
|
||||||
|
of "class":
|
||||||
|
result = p.options.flags.contains(pfCpp)
|
||||||
|
|
||||||
proc stmtKeyword(s: string): bool =
|
proc stmtKeyword(s: string): bool =
|
||||||
case s
|
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"):
|
(p.tok.s == "const" or p.tok.s == "volatile" or p.tok.s == "restrict"):
|
||||||
getTok(p, nil)
|
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 =
|
proc typeAtom(p: var TParser): PNode =
|
||||||
skipConst(p)
|
skipConst(p)
|
||||||
ExpectIdent(p)
|
ExpectIdent(p)
|
||||||
|
|
@ -451,6 +533,7 @@ proc typeAtom(p: var TParser): PNode =
|
||||||
else:
|
else:
|
||||||
result = mangledIdent(p.tok.s, p)
|
result = mangledIdent(p.tok.s, p)
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
|
result = optAngle(p, result)
|
||||||
|
|
||||||
proc newPointerTy(p: TParser, typ: PNode): PNode =
|
proc newPointerTy(p: TParser, typ: PNode): PNode =
|
||||||
if pfRefs in p.options.flags:
|
if pfRefs in p.options.flags:
|
||||||
|
|
@ -463,11 +546,26 @@ proc pointer(p: var TParser, a: PNode): PNode =
|
||||||
result = a
|
result = a
|
||||||
var i = 0
|
var i = 0
|
||||||
skipConst(p)
|
skipConst(p)
|
||||||
while p.tok.xkind == pxStar:
|
while true:
|
||||||
inc(i)
|
if p.tok.xkind == pxStar:
|
||||||
getTok(p, result)
|
inc(i)
|
||||||
skipConst(p)
|
getTok(p, result)
|
||||||
result = newPointerTy(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 a.kind == nkIdent and a.ident.s == "char":
|
||||||
if i >= 2:
|
if i >= 2:
|
||||||
result = newIdentNodeP("cstringArray", p)
|
result = newIdentNodeP("cstringArray", p)
|
||||||
|
|
@ -682,7 +780,7 @@ proc addTypeDef(section, name, t: PNode) =
|
||||||
proc otherTypeDef(p: var TParser, section, typ: PNode) =
|
proc otherTypeDef(p: var TParser, section, typ: PNode) =
|
||||||
var name: PNode
|
var name: PNode
|
||||||
var t = typ
|
var t = typ
|
||||||
if p.tok.xkind == pxStar:
|
if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp}:
|
||||||
t = pointer(p, t)
|
t = pointer(p, t)
|
||||||
if p.tok.xkind == pxParLe:
|
if p.tok.xkind == pxParLe:
|
||||||
# function pointer: typedef typ (*name)();
|
# function pointer: typedef typ (*name)();
|
||||||
|
|
@ -819,6 +917,12 @@ proc parseTypeDef(p: var TParser): PNode =
|
||||||
of "struct": parseTypedefStruct(p, result, isUnion=false)
|
of "struct": parseTypedefStruct(p, result, isUnion=false)
|
||||||
of "union": parseTypedefStruct(p, result, isUnion=true)
|
of "union": parseTypedefStruct(p, result, isUnion=true)
|
||||||
of "enum": parseTypedefEnum(p, result)
|
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:
|
else:
|
||||||
var t = typeAtom(p)
|
var t = typeAtom(p)
|
||||||
otherTypeDef(p, result, t)
|
otherTypeDef(p, result, t)
|
||||||
|
|
@ -871,22 +975,16 @@ proc parseVarDecl(p: var TParser, baseTyp, typ: PNode,
|
||||||
addSon(result, def)
|
addSon(result, def)
|
||||||
eat(p, pxSemicolon)
|
eat(p, pxSemicolon)
|
||||||
|
|
||||||
when false:
|
proc declarationName(p: var TParser): string =
|
||||||
proc declaration(p: var TParser, father: PNode) =
|
expectIdent(p)
|
||||||
# general syntax to parse is::
|
result = p.tok.s
|
||||||
#
|
getTok(p) # skip identifier
|
||||||
# baseType ::= typeIdent | ((struct|union|enum) ident ("{" body "}" )?
|
while p.tok.xkind == pxScope and pfCpp in p.options.flags:
|
||||||
# | "{" body "}")
|
getTok(p) # skip "::"
|
||||||
# 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)
|
expectIdent(p)
|
||||||
|
result.add("::")
|
||||||
|
result.add(p.tok.s)
|
||||||
|
getTok(p)
|
||||||
|
|
||||||
proc declaration(p: var TParser): PNode =
|
proc declaration(p: var TParser): PNode =
|
||||||
result = newNodeP(nkProcDef, p)
|
result = newNodeP(nkProcDef, p)
|
||||||
|
|
@ -908,9 +1006,7 @@ proc declaration(p: var TParser): PNode =
|
||||||
result = parseFunctionPointerDecl(p, rettyp)
|
result = parseFunctionPointerDecl(p, rettyp)
|
||||||
eat(p, pxSemicolon)
|
eat(p, pxSemicolon)
|
||||||
return
|
return
|
||||||
ExpectIdent(p)
|
var origName = declarationName(p)
|
||||||
var origName = p.tok.s
|
|
||||||
getTok(p) # skip identifier
|
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxParLe:
|
of pxParLe:
|
||||||
# really a function!
|
# really a function!
|
||||||
|
|
@ -918,7 +1014,9 @@ proc declaration(p: var TParser): PNode =
|
||||||
var params = newNodeP(nkFormalParams, p)
|
var params = newNodeP(nkFormalParams, p)
|
||||||
addReturnType(params, rettyp)
|
addReturnType(params, rettyp)
|
||||||
parseFormalParams(p, params, pragmas)
|
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:
|
if pfCDecl in p.options.flags:
|
||||||
addSon(pragmas, newIdentNodeP("cdecl", p))
|
addSon(pragmas, newIdentNodeP("cdecl", p))
|
||||||
elif pfStdcall in p.options.flags:
|
elif pfStdcall in p.options.flags:
|
||||||
|
|
@ -1027,10 +1125,10 @@ proc isDefinitelyAType(p: var TParser): bool =
|
||||||
while true:
|
while true:
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxSymbol:
|
of pxSymbol:
|
||||||
if declKeyword(p.tok.s): return true
|
if declKeyword(p, p.tok.s): return true
|
||||||
elif starFound: return false
|
elif starFound: return false
|
||||||
else: inc(words)
|
else: inc(words)
|
||||||
of pxStar:
|
of pxStar, pxAmp, pxAmpAmp:
|
||||||
starFound = true
|
starFound = true
|
||||||
of pxParRi: return words == 0 or words > 1 or starFound
|
of pxParRi: return words == 0 or words > 1 or starFound
|
||||||
else: return false
|
else: return false
|
||||||
|
|
@ -1205,6 +1303,10 @@ proc postfixExpression(p: var TParser): PNode =
|
||||||
addSon(result, newIdentNodeP("dec", p))
|
addSon(result, newIdentNodeP("dec", p))
|
||||||
gettok(p, result)
|
gettok(p, result)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
|
of pxLt:
|
||||||
|
if isTemplateAngleBracket(p):
|
||||||
|
result = optAngle(p, result)
|
||||||
|
else: break
|
||||||
else: break
|
else: break
|
||||||
|
|
||||||
proc unaryExpression(p: var TParser): PNode =
|
proc unaryExpression(p: var TParser): PNode =
|
||||||
|
|
@ -1224,7 +1326,22 @@ proc unaryExpression(p: var TParser): PNode =
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
if p.tok.xkind == pxParLe:
|
if p.tok.xkind == pxParLe:
|
||||||
getTok(p, result)
|
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)
|
eat(p, pxParRi, result)
|
||||||
else:
|
else:
|
||||||
addSon(result, unaryExpression(p))
|
addSon(result, unaryExpression(p))
|
||||||
|
|
@ -1455,14 +1572,14 @@ proc parseDoWhile(p: var TParser): PNode =
|
||||||
proc declarationOrStatement(p: var TParser): PNode =
|
proc declarationOrStatement(p: var TParser): PNode =
|
||||||
if p.tok.xkind != pxSymbol:
|
if p.tok.xkind != pxSymbol:
|
||||||
result = expressionStatement(p)
|
result = expressionStatement(p)
|
||||||
elif declKeyword(p.tok.s):
|
elif declKeyword(p, p.tok.s):
|
||||||
result = declaration(p)
|
result = declaration(p)
|
||||||
else:
|
else:
|
||||||
# ordinary identifier:
|
# ordinary identifier:
|
||||||
saveContext(p)
|
saveContext(p)
|
||||||
getTok(p) # skip identifier to look ahead
|
getTok(p) # skip identifier to look ahead
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxSymbol, pxStar:
|
of pxSymbol, pxStar, pxLt, pxAmp, pxAmpAmp:
|
||||||
# we parse
|
# we parse
|
||||||
# a b
|
# a b
|
||||||
# a * b
|
# a * b
|
||||||
|
|
@ -1630,11 +1747,288 @@ proc compoundStatement(p: var TParser): PNode =
|
||||||
if a.kind == nkEmpty: break
|
if a.kind == nkEmpty: break
|
||||||
embedStmts(result, a)
|
embedStmts(result, a)
|
||||||
if sonsLen(result) == 0:
|
if sonsLen(result) == 0:
|
||||||
# translate ``{}`` to Nimrod's ``nil`` statement
|
# translate ``{}`` to Nimrod's ``discard`` statement
|
||||||
result = newNodeP(nkNilLit, p)
|
result = newNodeP(nkDiscardStmt, p)
|
||||||
|
result.add(ast.emptyNode)
|
||||||
dec(p.scopeCounter)
|
dec(p.scopeCounter)
|
||||||
eat(p, pxCurlyRi)
|
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
|
include cpp
|
||||||
|
|
||||||
proc statement(p: var TParser): PNode =
|
proc statement(p: var TParser): PNode =
|
||||||
|
|
@ -1681,8 +2075,23 @@ proc statement(p: var TParser): PNode =
|
||||||
eat(p, pxSemicolon)
|
eat(p, pxSemicolon)
|
||||||
of "enum": result = enumSpecifier(p)
|
of "enum": result = enumSpecifier(p)
|
||||||
of "typedef": result = parseTypeDef(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)
|
else: result = declarationOrStatement(p)
|
||||||
of pxCurlyLe:
|
of pxCurlyLe:
|
||||||
result = compoundStatement(p)
|
result = compoundStatement(p)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ proc skipLine(p: var TParser) =
|
||||||
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
||||||
if p.tok.xkind == pxCurlyLe or
|
if p.tok.xkind == pxCurlyLe or
|
||||||
(p.tok.xkind == pxSymbol and (
|
(p.tok.xkind == pxSymbol and (
|
||||||
declKeyword(p.tok.s) or stmtKeyword(p.tok.s))):
|
declKeyword(p, p.tok.s) or stmtKeyword(p.tok.s))):
|
||||||
addSon(tmplDef, statement(p))
|
addSon(tmplDef, statement(p))
|
||||||
result = "stmt"
|
result = "stmt"
|
||||||
elif p.tok.xkind in {pxLineComment, pxNewLine}:
|
elif p.tok.xkind in {pxLineComment, pxNewLine}:
|
||||||
|
|
|
||||||
241
compiler/c2nim/tests/matrix.h
Normal file
241
compiler/c2nim/tests/matrix.h
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: wx/matrix.h
|
||||||
|
// Purpose: wxTransformMatrix class. NOT YET USED
|
||||||
|
// Author: Chris Breeze, Julian Smart
|
||||||
|
// Modified by: Klaas Holwerda
|
||||||
|
// Created: 01/02/97
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) Julian Smart, Chris Breeze
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _WX_MATRIXH__
|
||||||
|
#define _WX_MATRIXH__
|
||||||
|
|
||||||
|
//! headerfiles="matrix.h wx/object.h"
|
||||||
|
#include "wx/object.h"
|
||||||
|
#include "wx/math.h"
|
||||||
|
|
||||||
|
//! codefiles="matrix.cpp"
|
||||||
|
|
||||||
|
// A simple 3x3 matrix. This may be replaced by a more general matrix
|
||||||
|
// class some day.
|
||||||
|
//
|
||||||
|
// Note: this is intended to be used in wxDC at some point to replace
|
||||||
|
// the current system of scaling/translation. It is not yet used.
|
||||||
|
|
||||||
|
#def WXDLLIMPEXP_CORE
|
||||||
|
#header "wxmatrix.h"
|
||||||
|
|
||||||
|
//:definition
|
||||||
|
// A 3x3 matrix to do 2D transformations.
|
||||||
|
// It can be used to map data to window coordinates,
|
||||||
|
// and also for manipulating your own data.
|
||||||
|
// For example drawing a picture (composed of several primitives)
|
||||||
|
// at a certain coordinate and angle within another parent picture.
|
||||||
|
// At all times m_isIdentity is set if the matrix itself is an Identity matrix.
|
||||||
|
// It is used where possible to optimize calculations.
|
||||||
|
class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject<string, string<ubyte>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wxTransformMatrix(void);
|
||||||
|
wxTransformMatrix(const wxTransformMatrix& mat);
|
||||||
|
|
||||||
|
~wxTransformMatrix(void);
|
||||||
|
|
||||||
|
//get the value in the matrix at col,row
|
||||||
|
//rows are horizontal (second index of m_matrix member)
|
||||||
|
//columns are vertical (first index of m_matrix member)
|
||||||
|
double GetValue(int col, int row) const;
|
||||||
|
|
||||||
|
//set the value in the matrix at col,row
|
||||||
|
//rows are horizontal (second index of m_matrix member)
|
||||||
|
//columns are vertical (first index of m_matrix member)
|
||||||
|
void SetValue(int col, int row, double value);
|
||||||
|
|
||||||
|
void operator = (const wxTransformMatrix& mat);
|
||||||
|
bool operator == (const wxTransformMatrix& mat) const;
|
||||||
|
bool operator != (const wxTransformMatrix& mat) const;
|
||||||
|
|
||||||
|
//multiply every element by t
|
||||||
|
wxTransformMatrix& operator*=(const double& t);
|
||||||
|
//divide every element by t
|
||||||
|
wxTransformMatrix& operator/=(const double& t);
|
||||||
|
//add matrix m to this t
|
||||||
|
wxTransformMatrix& operator+=(const wxTransformMatrix& m);
|
||||||
|
//subtract matrix m from this
|
||||||
|
wxTransformMatrix& operator-=(const wxTransformMatrix& m);
|
||||||
|
//multiply matrix m with this
|
||||||
|
wxTransformMatrix& operator*=(const wxTransformMatrix& m);
|
||||||
|
|
||||||
|
// constant operators
|
||||||
|
|
||||||
|
//multiply every element by t and return result
|
||||||
|
wxTransformMatrix operator*(const double& t) const;
|
||||||
|
//divide this matrix by t and return result
|
||||||
|
wxTransformMatrix operator/(const double& t) const;
|
||||||
|
//add matrix m to this and return result
|
||||||
|
wxTransformMatrix operator+(const wxTransformMatrix& m) const;
|
||||||
|
//subtract matrix m from this and return result
|
||||||
|
wxTransformMatrix operator-(const wxTransformMatrix& m) const;
|
||||||
|
//multiply this by matrix m and return result
|
||||||
|
wxTransformMatrix operator*(const wxTransformMatrix& m) const;
|
||||||
|
wxTransformMatrix operator-() const;
|
||||||
|
|
||||||
|
//rows are horizontal (second index of m_matrix member)
|
||||||
|
//columns are vertical (first index of m_matrix member)
|
||||||
|
double& operator()(int col, int row);
|
||||||
|
|
||||||
|
//rows are horizontal (second index of m_matrix member)
|
||||||
|
//columns are vertical (first index of m_matrix member)
|
||||||
|
double operator()(int col, int row) const;
|
||||||
|
|
||||||
|
// Invert matrix
|
||||||
|
bool Invert(void);
|
||||||
|
|
||||||
|
// Make into identity matrix
|
||||||
|
bool Identity(void);
|
||||||
|
|
||||||
|
// Is the matrix the identity matrix?
|
||||||
|
// Only returns a flag, which is set whenever an operation
|
||||||
|
// is done.
|
||||||
|
inline bool IsIdentity(void) const { return m_isIdentity; }
|
||||||
|
|
||||||
|
// This does an actual check.
|
||||||
|
inline bool IsIdentity1(void) const ;
|
||||||
|
|
||||||
|
//Scale by scale (isotropic scaling i.e. the same in x and y):
|
||||||
|
//!ex:
|
||||||
|
//!code: | scale 0 0 |
|
||||||
|
//!code: matrix' = | 0 scale 0 | x matrix
|
||||||
|
//!code: | 0 0 scale |
|
||||||
|
bool Scale(double scale);
|
||||||
|
|
||||||
|
//Scale with center point and x/y scale
|
||||||
|
//
|
||||||
|
//!ex:
|
||||||
|
//!code: | xs 0 xc(1-xs) |
|
||||||
|
//!code: matrix' = | 0 ys yc(1-ys) | x matrix
|
||||||
|
//!code: | 0 0 1 |
|
||||||
|
wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc);
|
||||||
|
|
||||||
|
// mirror a matrix in x, y
|
||||||
|
//!ex:
|
||||||
|
//!code: | -1 0 0 |
|
||||||
|
//!code: matrix' = | 0 -1 0 | x matrix
|
||||||
|
//!code: | 0 0 1 |
|
||||||
|
wxTransformMatrix<float>& Mirror(bool x=true, bool y=false);
|
||||||
|
// Translate by dx, dy:
|
||||||
|
//!ex:
|
||||||
|
//!code: | 1 0 dx |
|
||||||
|
//!code: matrix' = | 0 1 dy | x matrix
|
||||||
|
//!code: | 0 0 1 |
|
||||||
|
bool Translate(double x, double y);
|
||||||
|
|
||||||
|
// Rotate clockwise by the given number of degrees:
|
||||||
|
//!ex:
|
||||||
|
//!code: | cos sin 0 |
|
||||||
|
//!code: matrix' = | -sin cos 0 | x matrix
|
||||||
|
//!code: | 0 0 1 |
|
||||||
|
bool Rotate(double angle);
|
||||||
|
|
||||||
|
//Rotate counter clockwise with point of rotation
|
||||||
|
//
|
||||||
|
//!ex:
|
||||||
|
//!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)|
|
||||||
|
//!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix
|
||||||
|
//!code: | 0 0 1 |
|
||||||
|
wxTransformMatrix& Rotate(const double &r, const double &x, const double &y);
|
||||||
|
|
||||||
|
// Transform X value from logical to device
|
||||||
|
inline double TransformX(double x) const;
|
||||||
|
|
||||||
|
// Transform Y value from logical to device
|
||||||
|
inline double TransformY(double y) const;
|
||||||
|
|
||||||
|
// Transform a point from logical to device coordinates
|
||||||
|
bool TransformPoint(double x, double y, double& tx, double& ty) const;
|
||||||
|
|
||||||
|
// Transform a point from device to logical coordinates.
|
||||||
|
// Example of use:
|
||||||
|
// wxTransformMatrix mat = dc.GetTransformation();
|
||||||
|
// mat.Invert();
|
||||||
|
// mat.InverseTransformPoint(x, y, x1, y1);
|
||||||
|
// OR (shorthand:)
|
||||||
|
// dc.LogicalToDevice(x, y, x1, y1);
|
||||||
|
// The latter is slightly less efficient if we're doing several
|
||||||
|
// conversions, since the matrix is inverted several times.
|
||||||
|
// N.B. 'this' matrix is the inverse at this point
|
||||||
|
bool InverseTransformPoint(double x, double y, double& tx, double& ty) const;
|
||||||
|
|
||||||
|
double Get_scaleX();
|
||||||
|
double Get_scaleY();
|
||||||
|
double GetRotation();
|
||||||
|
void SetRotation(double rotation);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
double m_matrix[3][3];
|
||||||
|
bool m_isIdentity;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Chris Breeze reported, that
|
||||||
|
some functions of wxTransformMatrix cannot work because it is not
|
||||||
|
known if he matrix has been inverted. Be careful when using it.
|
||||||
|
|
||||||
|
|
||||||
|
// Transform X value from logical to device
|
||||||
|
// warning: this function can only be used for this purpose
|
||||||
|
// because no rotation is involved when mapping logical to device coordinates
|
||||||
|
// mirror and scaling for x and y will be part of the matrix
|
||||||
|
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
||||||
|
// it in the logical coordinate system, use TransformPoint
|
||||||
|
inline double wxTransformMatrix::TransformX(double x) const
|
||||||
|
{
|
||||||
|
//normally like this, but since no rotation is involved (only mirror and scale)
|
||||||
|
//we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero
|
||||||
|
//(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]))
|
||||||
|
return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform Y value from logical to device
|
||||||
|
// warning: this function can only be used for this purpose
|
||||||
|
// because no rotation is involved when mapping logical to device coordinates
|
||||||
|
// mirror and scaling for x and y will be part of the matrix
|
||||||
|
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
||||||
|
// it in the logical coordinate system, use TransformPoint
|
||||||
|
inline double wxTransformMatrix::TransformY(double y) const
|
||||||
|
{
|
||||||
|
//normally like this, but since no rotation is involved (only mirror and scale)
|
||||||
|
//we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero
|
||||||
|
//(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]))
|
||||||
|
return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Is the matrix the identity matrix?
|
||||||
|
// Each operation checks whether the result is still the identity matrix and sets a flag.
|
||||||
|
inline bool wxTransformMatrix::IsIdentity1(void) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
( wxIsSameDouble(m_matrix[0][0], 1.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[1][1], 1.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[2][2], 1.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[1][0], 0.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[2][0], 0.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[0][1], 0.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[2][1], 0.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[0][2], 0.0) &&
|
||||||
|
wxIsSameDouble(m_matrix[1][2], 0.0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the determinant of a 2 x 2 matrix
|
||||||
|
inline double wxCalculateDet(double a11, double a21, double a12, double a22)
|
||||||
|
{
|
||||||
|
return a11 * a22 - a12 * a21;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif // _WX_MATRIXH__
|
||||||
|
|
@ -74,6 +74,7 @@ coordinate coord
|
||||||
rectangle rect
|
rectangle rect
|
||||||
point point
|
point point
|
||||||
symbol sym
|
symbol sym
|
||||||
|
literal lit
|
||||||
string str
|
string str
|
||||||
identifier ident
|
identifier ident
|
||||||
indentation indent
|
indentation indent
|
||||||
|
|
|
||||||
|
|
@ -4471,7 +4471,7 @@ proc with no side effects:
|
||||||
destructor pragma
|
destructor pragma
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The `destructor` pragma is used to mark a proc to act as a type destructor.
|
The `destructor`:idx: pragma is used to mark a proc to act as a type destructor.
|
||||||
The proc must have a single parameter with a concrete type (the name of a
|
The proc must have a single parameter with a concrete type (the name of a
|
||||||
generic type is allowed too).
|
generic type is allowed too).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
- Added ``macros.genSym`` builtin for AST generation.
|
- Added ``macros.genSym`` builtin for AST generation.
|
||||||
|
- Added ``macros.newLit`` procs for easier AST generation.
|
||||||
|
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
|
|
@ -56,6 +57,13 @@ Language Additions
|
||||||
- Support for user-defined type classes have been added.
|
- Support for user-defined type classes have been added.
|
||||||
|
|
||||||
|
|
||||||
|
Tools improvements
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- c2nim can deal with a subset of C++. Use the ``--cpp`` command line option
|
||||||
|
to activate.
|
||||||
|
|
||||||
|
|
||||||
2013-05-20 New website design!
|
2013-05-20 New website design!
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue