mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-20 16:01:29 +00:00
cn2im: basic C++ support
This commit is contained in:
@@ -19,6 +19,7 @@ c2nim - C to Nimrod source converter
|
||||
Usage: c2nim [options] inputfile [options]
|
||||
Options:
|
||||
-o, --out:FILE set output filename
|
||||
--cpp process C++ input file
|
||||
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
||||
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
||||
--cdecl annotate procs with ``{.cdecl.}``
|
||||
@@ -31,6 +32,8 @@ Options:
|
||||
--skipinclude do not convert ``#include`` to ``import``
|
||||
--typeprefixes generate ``T`` and ``P`` type prefixes
|
||||
--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
|
||||
-h, --help show this help
|
||||
"""
|
||||
|
||||
@@ -82,6 +82,8 @@ type
|
||||
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
|
||||
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
|
||||
pxComma, pxSemiColon, pxColon,
|
||||
pxAngleRi # '>' but determined to be the end of a
|
||||
# template's angle bracket
|
||||
TTokKinds* = set[TTokKind]
|
||||
|
||||
type
|
||||
@@ -202,6 +204,7 @@ proc TokKindToStr*(k: TTokKind): string =
|
||||
of pxColon: result = ":"
|
||||
of pxCurlyLe: result = "{"
|
||||
of pxCurlyRi: result = "}"
|
||||
of pxAngleRi: result = "> [end of template]"
|
||||
|
||||
proc `$`(tok: TToken): string =
|
||||
case tok.xkind
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ proc skipLine(p: var TParser) =
|
||||
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
||||
if p.tok.xkind == pxCurlyLe or
|
||||
(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))
|
||||
result = "stmt"
|
||||
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
|
||||
point point
|
||||
symbol sym
|
||||
literal lit
|
||||
string str
|
||||
identifier ident
|
||||
indentation indent
|
||||
|
||||
@@ -4471,7 +4471,7 @@ proc with no side effects:
|
||||
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
|
||||
generic type is allowed too).
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Library Additions
|
||||
-----------------
|
||||
|
||||
- Added ``macros.genSym`` builtin for AST generation.
|
||||
- Added ``macros.newLit`` procs for easier AST generation.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
@@ -56,6 +57,13 @@ Language Additions
|
||||
- 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!
|
||||
==============================
|
||||
|
||||
|
||||
Reference in New Issue
Block a user