From 6d80583d5a0e776fc9f4214fb96a532f3ebd5550 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 5 Apr 2012 19:20:52 +0300 Subject: [PATCH 1/8] Added ``global`` pragma that can be used to introduce new global variables from within procs --- compiler/ccgstmts.nim | 13 +++++++++---- compiler/options.nim | 2 +- compiler/pragmas.nim | 5 ++++- compiler/semexprs.nim | 6 ++++-- compiler/wordrecg.nim | 4 ++-- web/news.txt | 2 ++ 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 9c0d52221..f627ee036 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +# included from cgen.nim + const RangeExpandLimit = 256 # do not generate ranges # over 'RangeExpandLimit' elements @@ -48,16 +50,19 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = proc genSingleVar(p: BProc, a: PNode) = var v = a.sons[0].sym if sfCompileTime in v.flags: return + var targetProc = p var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags: - assignGlobalVar(p, v) - genObjectInit(p, cpsInit, v.typ, v.loc, true) + targetProc = p.module.initProc + assignGlobalVar(targetProc, v) + genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) else: assignLocalVar(p, v) initLocalVar(p, v, immediateAsgn) + if immediateAsgn: - genLineDir(p, a) - loadInto(p, a.sons[0], a.sons[2], v.loc) + genLineDir(targetProc, a) + loadInto(targetProc, a.sons[0], a.sons[2], v.loc) proc genClosureVar(p: BProc, a: PNode) = var immediateAsgn = a.sons[2].kind != nkEmpty diff --git a/compiler/options.nim b/compiler/options.nim index edea2288d..0d7763be0 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -221,4 +221,4 @@ proc binaryStrSearch*(x: openarray[string], y: string): int = # Can we keep this? I'm using it all the time template nimdbg*: expr = c.filename.endsWith"nimdbg.nim" - +template cnimdbg*: expr = p.module.filename.endsWith"nimdbg.nim" diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1ceacfc1c..7e632d858 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -51,7 +51,7 @@ const wImportcpp, wImportobjc, wError} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern, - wImportcpp, wImportobjc, wError, wNoInit, wCompileTime} + wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, wExtern, wImportcpp, wImportobjc, wError} letPragmas* = varPragmas @@ -494,6 +494,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = noVal(it) incl(sym.flags, sfCompileTime) incl(sym.loc.Flags, lfNoDecl) + of wGlobal: + noVal(it) + incl(sym.flags, sfGlobal) of wMerge: noval(it) incl(sym.flags, sfMerge) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0282c6c53..2475492cc 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -409,8 +409,10 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult = of nkSym: # don't list 'skLet' here: if n.sym.kind in {skVar, skResult, skTemp}: - if c.p.owner.id == n.sym.owner.id: result = arLocalLValue - else: result = arLValue + if c.p.owner.id == n.sym.owner.id and sfGlobal notin n.sym.flags: + result = arLocalLValue + else: + result = arLValue of nkDotExpr: if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: result = arLValue diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index a29f3e762..f96ba7751 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -58,7 +58,7 @@ type wWatchPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame, - wImplicitStatic + wImplicitStatic, wGlobal TSpecialWords* = set[TSpecialWord] @@ -107,7 +107,7 @@ const "watchpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit", - "nostackframe", "implicitstatic"] + "nostackframe", "implicitstatic", "global"] proc findStr*(a: openarray[string], s: string): int = for i in countup(low(a), high(a)): diff --git a/web/news.txt b/web/news.txt index 897961c25..fd2a50606 100755 --- a/web/news.txt +++ b/web/news.txt @@ -57,6 +57,8 @@ Language Additions - Added explicit ``static`` sections for enforced compile time evaluation. - ``addr`` is now treated like a prefix operator syntactically. +- Added ``global`` pragma that can be used to introduce new global variables + from within procs. 2012-02-09 Version 0.8.14 released From 98b7bdaa5050a9b3709e8a27fd44477a2a28e4f7 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 5 Apr 2012 22:43:37 +0300 Subject: [PATCH 2/8] when expressions, proper rendering for nkDo and nkLambda and parser support for x.type and x.addr --- compiler/ast.nim | 7 ++++++- compiler/parser.nim | 31 +++++++++++++++++++++---------- compiler/renderer.nim | 26 +++++++++++++++++++++----- compiler/semexprs.nim | 3 +++ compiler/semstmts.nim | 4 ++-- web/news.txt | 3 ++- 6 files changed, 55 insertions(+), 19 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 897501ee5..972ba7924 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -143,7 +143,7 @@ type nkPragma, # a pragma statement nkPragmaBlock, # a pragma with a block nkIfStmt, # an if statement - nkWhenStmt, # a when statement + nkWhenStmt, # a when expression or statement nkForStmt, # a for statement nkWhileStmt, # a while statement nkCaseStmt, # a case statement @@ -246,6 +246,11 @@ const sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded # without considering any possible overloads +const + # getting ready for the future expr/stmt merge + nkWhen* = nkWhenStmt + nkWhenExpr* = nkWhenStmt + type TTypeKind* = enum # order is important! # Don't forget to change hti.nim if you make a change here diff --git a/compiler/parser.nim b/compiler/parser.nim index 2ba04ed1b..9563849c6 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -264,16 +264,26 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) = optInd(p, a) eat(p, endTok) -proc newDotExpr(p: var TParser, a: PNode): PNode = +proc dotExpr(p: var TParser, a: PNode): PNode = getTok(p) optInd(p, a) - result = newNodeI(nkDotExpr, a.info) - addSon(result, a) - addSon(result, parseSymbol(p)) + case p.tok.tokType + of tkType: + result = newNodeP(nkTypeOfExpr, p) + getTok(p) + addSon(result, a) + of tkAddr: + result = newNodeP(nkAddr, p) + getTok(p) + addSon(result, a) + else: + result = newNodeI(nkDotExpr, a.info) + addSon(result, a) + addSon(result, parseSymbol(p)) proc qualifiedIdent(p: var TParser): PNode = result = parseSymbol(p) #optInd(p, result); - if p.tok.tokType == tkDot: result = newDotExpr(p, result) + if p.tok.tokType == tkDot: result = dotExpr(p, result) proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) = getTok(p) @@ -477,7 +487,7 @@ proc primary(p: var TParser): PNode = exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result) parseDoBlocks(p, result) of tkDot: - result = newDotExpr(p, result) + result = dotExpr(p, result) result = parseGStrLit(p, result) of tkBracketLe: result = indexExprList(p, result, nkBracketExpr, tkBracketRi) @@ -506,8 +516,8 @@ proc lowestExprAux(p: var TParser, limit: int): PNode = proc lowestExpr(p: var TParser): PNode = result = lowestExprAux(p, -1) -proc parseIfExpr(p: var TParser): PNode = - result = newNodeP(nkIfExpr, p) +proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = + result = newNodeP(kind, p) while true: getTok(p) # skip `if`, `elif` var branch = newNodeP(nkElifExpr, p) @@ -707,7 +717,8 @@ proc parseExpr(p: var TParser): PNode = of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr) of tkTuple: result = parseTuple(p) of tkProc: result = parseProcExpr(p, true) - of tkIf: result = parseIfExpr(p) + of tkIf: result = parseIfExpr(p, nkIfExpr) + of tkWhen: result = parseIfExpr(p, nkWhenExpr) else: result = lowestExpr(p) proc parseTypeDesc(p: var TParser): PNode = @@ -718,7 +729,7 @@ proc isExprStart(p: TParser): bool = case p.tok.tokType of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, - tkTuple, tkType: + tkTuple, tkType, tkWhen: result = true else: result = false diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 0be578a1a..6545b2e72 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -349,7 +349,8 @@ proc lsub(n: PNode): int = of nkBind: result = lsons(n) + len("bind_") of nkBindStmt: result = lcomma(n) + len("bind_") of nkCheckedFieldExpr: result = lsub(n.sons[0]) - of nkLambda, nkDo: result = lsons(n) + len("lambda__=_") # XXX: render nkDo + of nkLambda: result = lsons(n) + len("proc__=_") + of nkDo: result = lsons(n) + len("do__:_") of nkConstDef, nkIdentDefs: result = lcomma(n, 0, - 3) var L = sonsLen(n) @@ -673,7 +674,17 @@ proc gident(g: var TSrcGen, n: PNode) = t = tkOpr put(g, t, s) if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id) + +proc doParamsAux(g: var TSrcGen, params: PNode) = + if params.len > 1: + put(g, tkParLe, "(") + gcomma(g, params, 1) + put(g, tkParRi, ")") + if params.sons[0].kind != nkEmpty: + putWithSpace(g, tkOpr, "->") + gsub(g, params.sons[0]) + proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if isNil(n): return var @@ -800,14 +811,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsub(g, n.sons[0]) of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]) - of nkLambda, nkDo: # XXX: nkDo is rendered as regular lambda - assert(n.sons[genericParamsPos].kind == nkEmpty) - putWithSpace(g, tkLambda, "lambda") + of nkLambda: + putWithSpace(g, tkLambda, "proc") gsub(g, n.sons[paramsPos]) gsub(g, n.sons[pragmasPos]) put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, n.sons[bodyPos]) + of nkDo: + putWithSpace(g, tkDo, "do") + doParamsAux(g, n.sons[paramsPos]) + gsub(g, n.sons[pragmasPos]) + put(g, tkColon, ":") + gsub(g, n.sons[bodyPos]) of nkConstDef, nkIdentDefs: gcomma(g, n, 0, - 3) var L = sonsLen(n) @@ -956,7 +972,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkIfStmt: putWithSpace(g, tkIf, "if") gif(g, n) - of nkWhenStmt, nkRecWhen: + of nkWhen, nkRecWhen: putWithSpace(g, tkWhen, "when") gif(g, n) of nkWhileStmt: gwhile(g, n) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2475492cc..8ab4c5f63 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1356,6 +1356,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semIndirectOp(c, n, flags) of nkMacroStmt: result = semMacroStmt(c, n) + of nkWhenExpr: + result = semWhen(c, n, false) + result = semExpr(c, result) of nkBracketExpr: checkMinSonsLen(n, 1) var s = qualifiedLookup(c, n.sons[0], {checkUndeclared}) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2de496b9a..0449c5644 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -25,13 +25,13 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] case it.kind - of nkElifBranch: + of nkElifBranch, nkElifExpr: checkSonsLen(it, 2) var e = semAndEvalConstExpr(c, it.sons[0]) if e.kind != nkIntLit: InternalError(n.info, "semWhen") if e.intVal != 0 and result == nil: setResult(it.sons[1]) - of nkElse: + of nkElse, nkElseExpr: checkSonsLen(it, 1) if result == nil: setResult(it.sons[0]) diff --git a/web/news.txt b/web/news.txt index fd2a50606..dd1d55a18 100755 --- a/web/news.txt +++ b/web/news.txt @@ -58,7 +58,8 @@ Language Additions - Added explicit ``static`` sections for enforced compile time evaluation. - ``addr`` is now treated like a prefix operator syntactically. - Added ``global`` pragma that can be used to introduce new global variables - from within procs. + from within procs. +- when expressions are now allowed just like if expressions 2012-02-09 Version 0.8.14 released From efb53233cb3434b94b28060f0a642c51049cb09d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 6 Apr 2012 05:02:48 +0300 Subject: [PATCH 3/8] the foundations of a type traits module; better error messages for expr, typedesc and typeclasses params --- compiler/ast.nim | 8 +++++++- compiler/evals.nim | 20 +++++++++++++++++++- compiler/msgs.nim | 3 +++ compiler/semexprs.nim | 10 +++++----- compiler/semfold.nim | 2 +- compiler/semmagic.nim | 11 +++++++++++ compiler/semtypes.nim | 6 +++--- compiler/types.nim | 17 ++++++++++++++++- 8 files changed, 65 insertions(+), 12 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 972ba7924..c6a2b32e7 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -243,8 +243,13 @@ const sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfNoInit* = sfMainModule # don't generate code to init the variable + sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded # without considering any possible overloads + + sfAnon* = sfCompilerProc # symbol name that was generated by the compiler + # the compiler will avoid printing such names + # in user messages. const # getting ready for the future expr/stmt merge @@ -358,7 +363,8 @@ const type TMagic* = enum # symbols that require compiler magic: - mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, mOf, + mNone, + mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mEcho, mShallowCopy, mSlurp, mParseExprToAst, mParseStmtToAst, mExpandToAst, mUnaryLt, mSucc, diff --git a/compiler/evals.nim b/compiler/evals.nim index 84d3023a5..92726ae31 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -490,7 +490,7 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode = proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = var s = n.sym case s.kind - of skProc, skConverter, skMacro: + of skProc, skConverter, skMacro, skType: result = n #result = s.getBody of skVar, skLet, skForVar, skTemp, skResult: @@ -891,7 +891,24 @@ proc evalTemplate*(n: PNode, sym: PSym): PNode = result = evalTemplateAux(sym.getBody, args, sym) dec(evalTemplateCounter) + +proc evalTypeTrait*(n: PNode, context: PSym): PNode = + ## XXX: This should be pretty much guaranteed to be true + # by the type traits procs' signitures, but until the + # code is more mature it doesn't hurt to be extra safe + internalAssert n.sons.len >= 2 and + n.sons[1].sym.typ.kind == tyTypeDesc + let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc}) + case n.sons[0].sym.name.s + of "name": + result = newStrNode(nkStrLit, typ.typeToString) + result.typ = newType(tyString, context) + result.info = n.info + + else: + internalAssert false + proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = var n = original.copyTree @@ -941,6 +958,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = of mParseExprToAst: result = evalParseExpr(c, n) of mParseStmtToAst: result = evalParseStmt(c, n) of mExpandToAst: result = evalExpandToAst(c, n) + of mTypeTrait: result = evalTypeTrait(n, c.module) of mNLen: result = evalAux(c, n.sons[1], {efLValue}) if isSpecial(result): return diff --git a/compiler/msgs.nim b/compiler/msgs.nim index df9064ab2..87f5e5650 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -667,3 +667,6 @@ template AssertNotNil*(e: expr): expr = if(e == nil): InternalError($InstantiationInfo()) e +template InternalAssert*(e: bool): stmt = + if not e: InternalError($InstantiationInfo()) + diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8ab4c5f63..bca27a43d 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1314,11 +1314,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = Message(n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) of nkTypeOfExpr: - var typ = semTypeNode(c, n, nil) - if typ.sym == nil: - typ = copyType(typ, typ.owner, true) - typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner)) - result = newSymNode(typ.sym, n.info) + var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) + typ = makeTypedesc(c, typ) + var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ) + sym.flags.incl(sfAnon) + result = newSymNode(sym, n.info) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 956667091..82ee7de13 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -206,7 +206,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mNewString, mNewStringOfCap, mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, - mParseExprToAst, mParseStmtToAst, mExpandToAst, + mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mNLen..mNError, mEqRef: nil of mRand: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 4f120e2ab..e6861f2e4 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -8,6 +8,7 @@ # # This include file implements the semantic checking for magics. +# included from sem.nim proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode = var r = isPartOf(n[1], n[2]) @@ -43,11 +44,21 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode = result.add(filename) result.add(line) +proc semTypeTraits(c: PContext, n: PNode): PNode = + checkMinSonsLen(n, 2) + internalAssert n.sons[1].kind == nkSym + if n.sons[1].sym.kind == skType: + result = evalTypeTrait(n, GetCurrOwner()) + else: + # pass unmodified to evals + result = n + proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = case n[0].sym.magic of mSlurp: result = semSlurp(c, n, flags) of mIsPartOf: result = semIsPartOf(c, n, flags) + of mTypeTrait: result = semTypeTraits(c, n) of mAstToStr: result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result.typ = getSysType(tyString) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 38cf19406..8479810d2 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -583,8 +583,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, break addImplicitGeneric var s = newSym(skType, paramTypId, getCurrOwner()) - s.typ = typeClass - s.typ.sym = s + s.flags.incl(sfAnon) + s.linkTo(typeClass) s.position = genericParams.len genericParams.addSon(newSymNode(s)) endingType = typeClass @@ -693,7 +693,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkTypeOfExpr: # for ``type(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1) - result = semExprWithType(c, n.sons[0], {efInTypeof}).typ + result = semExprWithType(c, n.sons[0], {efInTypeof, efAllowType}).typ of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) else: GlobalError(n.info, errTypeExpected) diff --git a/compiler/types.nim b/compiler/types.nim index 3f7c2c820..15390bed7 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -372,6 +372,13 @@ proc rangeToStr(n: PNode): string = assert(n.kind == nkRange) result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1]) +proc constraintsToStr(t: PType): string = + let sep = if tfAny in t.flags: " or " else: " and " + result = "" + for i in countup(0, t.sons.len - 1): + if i > 0: result.add(sep) + result.add(t.sons[i].typeToString) + proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = const typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", @@ -387,7 +394,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ result = "" if t == nil: return - if prefer == preferName and t.sym != nil: + if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags: return t.sym.Name.s case t.Kind of tyGenericBody, tyGenericInst, tyGenericInvokation: @@ -396,6 +403,14 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i > 1: add(result, ", ") add(result, typeToString(t.sons[i])) add(result, ']') + of tyTypeDesc: + if t.sons.len == 0: result = "typedesc" + else: result = "typedesc{" & constraintsToStr(t) & "}" + of tyTypeClass: + result = constraintsToStr(t) + of tyExpr: + if t.sons.len == 0: result = "expr" + else: result = "expr{" & constraintsToStr(t) & "}" of tyArray: if t.sons[0].kind == tyRange: result = "array[" & rangeToStr(t.sons[0].n) & ", " & From e941a147670442e706d1777f4a1bc368d0cbcdba Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 6 Apr 2012 18:14:12 +0300 Subject: [PATCH 4/8] completing the "types as first class values" reform --- compiler/msgs.nim | 3 +- compiler/sem.nim | 2 +- compiler/semexprs.nim | 83 ++++++++++++++++++++++++------------------- compiler/semtypes.nim | 2 +- 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 87f5e5650..a0058ebe3 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -72,7 +72,7 @@ type errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, - errXNotAllowedHere, errInvalidControlFlowX, errATypeHasNoValue, + errXNotAllowedHere, errInvalidControlFlowX, errXisNoType, errCircumNeedsPointer, errInvalidExpression, errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, errNamedExprNotAllowed, errXExpectsOneTypeParam, @@ -275,7 +275,6 @@ const errInvalidPragmaX: "invalid pragma: $1", errXNotAllowedHere: "$1 not allowed here", errInvalidControlFlowX: "invalid control flow: $1", - errATypeHasNoValue: "a type has no value", errXisNoType: "invalid type: \'$1\'", errCircumNeedsPointer: "'[]' needs a pointer or reference type", errInvalidExpression: "invalid expression", diff --git a/compiler/sem.nim b/compiler/sem.nim index e27f20503..8afbe3c51 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -21,7 +21,7 @@ proc semPass*(): TPass type TExprFlag = enum - efAllowType, efLValue, efWantIterator, efInTypeof + efLValue, efWantIterator, efInTypeof TExprFlags = set[TExprFlag] proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index bca27a43d..d2a19cb86 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,7 +10,16 @@ # this module does the semantic checking for expressions # included from sem.nim -proc semExprOrTypedesc(c: PContext, n: PNode): PNode +proc restoreOldStyleType(n: PNode) = + # XXX: semExprWithType used to return the same type + # for nodes such as (100) or (int). + # This is inappropriate. The type of the first expression + # should be "int", while the type of the second one should + # be typedesc(int). + # + # This is strictly for backward compatibility until + # the transition to types as first-class values is complete. + n.typ = n.typ.skipTypes({tyTypeDesc}) proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = markUsed(n, s) @@ -108,10 +117,9 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = if s.ast == nil: InternalError(n.info, "no default for") result = semExpr(c, s.ast) of skType: - if efAllowType notin flags: - GlobalError(n.info, errATypeHasNoValue) markUsed(n, s) result = newSymNode(s, n.info) + result.typ = makeTypeDesc(c, s.typ) else: markUsed(n, s) result = newSymNode(s, n.info) @@ -206,7 +214,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = if sonsLen(n) != 2: GlobalError(n.info, errXExpectsTypeOrValue, opToStr[m]) else: - n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType}) + n.sons[1] = semExprWithType(c, n.sons[1]) + restoreOldStyleType(n.sons[1]) var typ = skipTypes(n.sons[1].typ, abstractVarRange) case typ.Kind of tySequence, tyString, tyOpenArray: @@ -219,15 +228,21 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = result = n proc semSizeof(c: PContext, n: PNode): PNode = - if sonsLen(n) != 2: GlobalError(n.info, errXExpectsTypeOrValue, "sizeof") - else: n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType}) + if sonsLen(n) != 2: + GlobalError(n.info, errXExpectsTypeOrValue, "sizeof") + else: + n.sons[1] = semExprWithType(c, n.sons[1]) + restoreOldStyleType(n.sons[1]) + n.typ = getSysType(tyInt) result = n proc semOf(c: PContext, n: PNode): PNode = if sonsLen(n) == 3: - n.sons[1] = semExprWithType(c, n.sons[1], {efAllowType}) - n.sons[2] = semExprWithType(c, n.sons[2], {efAllowType}) + n.sons[1] = semExprWithType(c, n.sons[1]) + n.sons[2] = semExprWithType(c, n.sons[2]) + restoreOldStyleType(n.sons[1]) + restoreOldStyleType(n.sons[2]) var a = skipTypes(n.sons[1].typ, abstractPtrs) var b = skipTypes(n.sons[2].typ, abstractPtrs) if b.kind != tyObject or a.kind != tyObject: @@ -251,31 +266,16 @@ proc semIs(c: PContext, n: PNode): PNode = else: GlobalError(n.info, errXExpectsTwoArguments, "is") -proc semExprOrTypedesc(c: PContext, n: PNode): PNode = - # XXX: Currently, semExprWithType will return the same type - # for nodes such as (100) or (int). - # This is inappropriate. The type of the first expression - # should be "int", while the type of the second one should - # be typeDesc(int). - # Ideally, this should be fixed in semExpr, but right now - # there are probably users that depend on the present behavior. - # XXX: Investigate current uses of efAllowType and fix them to - # work with tyTypeDesc. - result = semExprWithType(c, n, {efAllowType}) - if result.kind == nkSym and result.sym.kind == skType and - result.typ.kind != tyTypeDesc: - result.typ = makeTypeDesc(c, result.typ) - proc semOpAux(c: PContext, n: PNode) = for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkExprEqExpr and sonsLen(a) == 2: var info = a.sons[0].info a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info) - a.sons[1] = semExprOrTypedesc(c, a.sons[1]) + a.sons[1] = semExprWithType(c, a.sons[1]) a.typ = a.sons[1].typ else: - n.sons[i] = semExprOrTypedesc(c, a) + n.sons[i] = semExprWithType(c, a) proc overloadedCallOpr(c: PContext, n: PNode): PNode = # quick check if there is *any* () operator overloaded: @@ -754,13 +754,15 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = return semSym(c, n, s, flags) checkSonsLen(n, 2) - n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags) + n.sons[0] = semExprWithType(c, n.sons[0], flags) + restoreOldStyleType(n.sons[0]) var i = considerAcc(n.sons[1]) - var ty = n.sons[0].Typ + var ty = n.sons[0].typ var f: PSym = nil result = nil if isTypeExpr(n.sons[0]): - if ty.kind == tyEnum: + case ty.kind + of tyEnum: # look up if the identifier belongs to the enum: while ty != nil: f = getSymFromList(ty.n, i) @@ -771,10 +773,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result.info = n.info result.typ = ty markUsed(n, f) - return - elif efAllowType notin flags: - GlobalError(n.sons[0].info, errATypeHasNoValue) + return + of tyGenericInst: + assert ty.sons[0].kind == tyGenericBody + let tbody = ty.sons[0] + for s in countup(0, tbody.len-2): + let tParam = tbody.sons[s] + assert tParam.kind == tyGenericParam + if tParam.sym.name == i: + let foundTyp = makeTypeDesc(c, ty.sons[s + 1]) + return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info) return + else: + # echo "TYPE FIELD ACCESS" + # debug ty + return + # XXX: This is probably not relevant any more # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim": ty = n.sons[0].Typ @@ -854,14 +868,14 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return checkMinSonsLen(n, 2) - n.sons[0] = semExprOrTypedesc(c, n.sons[0]) + n.sons[0] = semExprWithType(c, n.sons[0]) var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString: checkSonsLen(n, 2) n.sons[0] = makeDeref(n.sons[0]) for i in countup(1, sonsLen(n) - 1): - n.sons[i] = semExprWithType(c, n.sons[i], flags - {efAllowType}) + n.sons[i] = semExprWithType(c, n.sons[i], flags) var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt) var arg = IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]) if arg != nil: @@ -1282,9 +1296,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = nil of nkNilLit: result.typ = getSysType(tyNil) - of nkType: - if not (efAllowType in flags): GlobalError(n.info, errATypeHasNoValue) - n.typ = semTypeNode(c, n, nil) of nkIntLit: if result.typ == nil: result.typ = getSysType(tyInt) of nkInt8Lit: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 8479810d2..be5bd95d9 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -693,7 +693,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkTypeOfExpr: # for ``type(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1) - result = semExprWithType(c, n.sons[0], {efInTypeof, efAllowType}).typ + result = semExprWithType(c, n.sons[0], {efInTypeof}).typ of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) else: GlobalError(n.info, errTypeExpected) From a64f03230afa69f2143b0eb159c9294998c5e19b Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Tue, 10 Apr 2012 20:53:44 +0300 Subject: [PATCH 5/8] proper order of initialization for .global. variables --- compiler/ccgstmts.nim | 2 +- compiler/cgen.nim | 6 +++++- compiler/cgendata.nim | 4 ++++ doc/manual.txt | 18 +++++++++++++++++- tests/run/globalaux.nim | 15 +++++++++++++++ tests/run/globalaux2.nim | 4 ++++ tests/run/tglobal.nim | 16 ++++++++++++++++ 7 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 tests/run/globalaux.nim create mode 100644 tests/run/globalaux2.nim create mode 100644 tests/run/tglobal.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f627ee036..e018a3ac9 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -53,7 +53,7 @@ proc genSingleVar(p: BProc, a: PNode) = var targetProc = p var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags: - targetProc = p.module.initProc + targetProc = p.module.preInitProc assignGlobalVar(targetProc, v) genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) else: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a56053f79..de91205e2 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -859,6 +859,7 @@ proc genInitCode(m: BModule) = app(prc, genSectionStart(cpsLocals)) app(prc, m.initProc.s[cpsLocals]) + app(prc, m.preInitProc.s[cpsLocals]) app(prc, genSectionEnd(cpsLocals)) app(prc, genSectionStart(cfsTypeInit1)) @@ -875,10 +876,12 @@ proc genInitCode(m: BModule) = app(prc, genSectionEnd(i)) app(prc, genSectionStart(cpsInit)) + app(prc, m.preInitProc.s[cpsInit]) app(prc, m.initProc.s[cpsInit]) app(prc, genSectionEnd(cpsInit)) - app(prc, genSectionStart(cpsStmts)) + app(prc, genSectionStart(cpsStmts)) + app(prc, m.preInitProc.s[cpsStmts]) app(prc, m.initProc.s[cpsStmts]) if optStackTrace in m.initProc.options and not m.PreventStackTrace: app(prc, deinitFrame(m.initProc)) @@ -916,6 +919,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = result.typeInfoMarker = initIntSet() result.initProc = newProc(nil, result) result.initProc.options = gOptions + result.preInitProc = newProc(nil, result) initNodeTable(result.dataCache) result.typeStack = @[] result.forwardedProcs = @[] diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index c58c64250..fafccce18 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -93,6 +93,10 @@ type headerFiles*: TLinkedList # needed headers to include typeInfoMarker*: TIntSet # needed for generating type information initProc*: BProc # code for init procedure + preInitProc*: BProc # code executed before the init proc + # used for initialization code for + # .global. variables + # (or instantiated generic variables) typeStack*: TTypeSeq # used for type generation dataCache*: TNodeTable forwardedProcs*: TSymSeq # keep forwarded procs here diff --git a/doc/manual.txt b/doc/manual.txt index 9b5362324..9618bdbc7 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -3267,7 +3267,7 @@ but are used to override the settings temporarily. Example: {.pop.} # restore old settings -Register pragma +register pragma --------------- The `register`:idx: pragma is for variables only. It declares the variable as ``register``, giving the compiler a hint that the variable should be placed @@ -3277,6 +3277,22 @@ though and for good reasons: Often they do a better job without it anyway. In highly specific cases (a dispatch loop of an bytecode interpreter for example) it may provide benefits, though. +global pragma +--------------- +The `global`:idx pragma can be applied to a variable within a proc to instruct +the compiler to store it in a global location and initialize it once at program +startup. + +.. code-block:: nimrod +proc isHexNumber(s: string): bool = + var pattern {.global.} = re"[0-9a-fA-F]+" + result = s.match(pattern) + +When used within a generic proc, a separate unique global variable will be +created for each instantiation of the proc. The order of initialization of +the created global variables within a module is not defined, but all of them +will be initialized after any top-level variables in their originating module +and before any variable in a module that imports it. DeadCodeElim pragma ------------------- diff --git a/tests/run/globalaux.nim b/tests/run/globalaux.nim new file mode 100644 index 000000000..5f6f72721 --- /dev/null +++ b/tests/run/globalaux.nim @@ -0,0 +1,15 @@ +type + TObj*[T] = object + val*: T + +var + totalGlobals* = 0 + +proc makeObj[T](x: T): TObj[T] = + totalGlobals += 1 + result.val = x + +proc globalInstance*[T]: var TObj[T] = + var g {.global.} = when T is int: makeObj(10) else: makeObj("hello") + result = g + diff --git a/tests/run/globalaux2.nim b/tests/run/globalaux2.nim new file mode 100644 index 000000000..6c77f1f48 --- /dev/null +++ b/tests/run/globalaux2.nim @@ -0,0 +1,4 @@ +import globalaux + +echo "in globalaux2: ", globalInstance[int]().val + diff --git a/tests/run/tglobal.nim b/tests/run/tglobal.nim new file mode 100644 index 000000000..84c4510c1 --- /dev/null +++ b/tests/run/tglobal.nim @@ -0,0 +1,16 @@ +discard """ + file: "toop1.nim" + output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second" +""" + +import globalaux, globalaux2 + +echo "total globals: ", totalGlobals + +globalInstance[int]().val = 100 +echo "int value: ", globalInstance[int]().val + +globalInstance[string]().val = "first" +globalInstance[string]().val = "second" +echo "string value: ", globalInstance[string]().val + From 97ab16d46b55aa9a4b2acbc72777fb6a8d5a162f Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Tue, 10 Apr 2012 22:32:23 +0300 Subject: [PATCH 6/8] typetraits module and tests --- lib/pure/typetraits.nim | 15 +++++++++++++++ tests/run/ttypetraits.nim | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 lib/pure/typetraits.nim create mode 100644 tests/run/ttypetraits.nim diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim new file mode 100644 index 000000000..45b79dcb6 --- /dev/null +++ b/lib/pure/typetraits.nim @@ -0,0 +1,15 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Nimrod Contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module defines compile-time reflection procs for +## working with types + +proc name*(t: typedesc): string {.magic: "TypeTrait".} + ## Returns the name of the given type + diff --git a/tests/run/ttypetraits.nim b/tests/run/ttypetraits.nim new file mode 100644 index 000000000..5b683bef0 --- /dev/null +++ b/tests/run/ttypetraits.nim @@ -0,0 +1,24 @@ +discard """ + msg: "int\nstring\nTBar[int]" + output: "int\nstring\nTBar[int]" +""" + +import typetraits + +proc foo(x) = + static: + var t = type(x) + echo t.name + + echo x.type.name + +type + TBar[U] = object + x: U + +var bar: TBar[int] + +foo 10 +foo "test" +foo bar + From 238202ccbc418dece73086f0d009b2b6fe3850ca Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 11 Apr 2012 01:14:56 +0300 Subject: [PATCH 7/8] re-enable rodfiles tests; fixes #91 --- compiler/ccgstmts.nim | 3 ++- compiler/semtypes.nim | 7 ++++++- tests/reject/ttypenoval.nim | 2 +- tests/rodfiles/bmethods.nim | 1 - tests/rodfiles/bmethods2.nim | 1 - tests/run/tenumitems.nim | 14 ++++++++++++++ tests/specials.nim | 3 ++- 7 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 tests/run/tenumitems.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e018a3ac9..5ad9d8b44 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -53,7 +53,8 @@ proc genSingleVar(p: BProc, a: PNode) = var targetProc = p var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags: - targetProc = p.module.preInitProc + if v.owner.kind != skModule: + targetProc = p.module.preInitProc assignGlobalVar(targetProc, v) genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) else: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index be5bd95d9..5626da6f9 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -181,7 +181,12 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if result != nil: markUsed(n, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: - return result.typ.sons[0].sym + # This is a typedesc param. is it already bound? + # it's not bound when it's also used as return type for example + if result.typ.sonsLen > 0: + return result.typ.sons[0].sym + else: + return result.typ.sym if result.kind != skType: GlobalError(n.info, errTypeExpected) if result.typ.kind != tyGenericParam: # XXX get rid of this hack! diff --git a/tests/reject/ttypenoval.nim b/tests/reject/ttypenoval.nim index 9944e52a1..6362407ef 100755 --- a/tests/reject/ttypenoval.nim +++ b/tests/reject/ttypenoval.nim @@ -1,7 +1,7 @@ discard """ file: "ttypenoval.nim" line: 38 - errormsg: "a type has no value" + errormsg: "type mismatch: got (typedesc{int}) but expected 'int'" """ # A min-heap. diff --git a/tests/rodfiles/bmethods.nim b/tests/rodfiles/bmethods.nim index 39aa5368c..995942ad6 100644 --- a/tests/rodfiles/bmethods.nim +++ b/tests/rodfiles/bmethods.nim @@ -1,5 +1,4 @@ discard """ - disabled: true output: '''derived class base class ''' diff --git a/tests/rodfiles/bmethods2.nim b/tests/rodfiles/bmethods2.nim index 0d1795a27..7ffb27f15 100644 --- a/tests/rodfiles/bmethods2.nim +++ b/tests/rodfiles/bmethods2.nim @@ -1,5 +1,4 @@ discard """ - disabled: true output: '''derived class 2 base class ''' diff --git a/tests/run/tenumitems.nim b/tests/run/tenumitems.nim new file mode 100644 index 000000000..516839fb3 --- /dev/null +++ b/tests/run/tenumitems.nim @@ -0,0 +1,14 @@ +discard """ + output: "A\nB\nC" +""" + +type TAlphabet = enum + A, B, C + +iterator items(E: typedesc): E = + for v in low(E)..high(E): + yield v + +for c in TAlphabet: + echo($c) + diff --git a/tests/specials.nim b/tests/specials.nim index 05eda6061..3dc083f2e 100644 --- a/tests/specials.nim +++ b/tests/specials.nim @@ -22,7 +22,8 @@ proc delNimCache() = except EOS: echo "[Warning] could not delete: ", dir -proc plusCache(options: string): string = return options & " --symbolFiles:on" +proc plusCache(options: string): string = return options & + " --symbolFiles:on --nimcache:./nimcache" proc runRodFiles(r: var TResults, options: string) = template test(filename: expr): stmt = From bac790ae3b40fd66920c9b63b67f02bbc13f5e68 Mon Sep 17 00:00:00 2001 From: dom96 Date: Wed, 11 Apr 2012 20:45:27 +0100 Subject: [PATCH 8/8] The build.sh file generated by niminst now supports a --extraBuildArgs param. --- tools/niminst/buildsh.tmpl | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl index 1f15901cc..936378de2 100755 --- a/tools/niminst/buildsh.tmpl +++ b/tools/niminst/buildsh.tmpl @@ -3,9 +3,30 @@ # result = "#! /bin/sh\n# Generated from niminst\n" & # "# Template is in tools/buildsh.tmpl\n" & # "# To regenerate run ``niminst csource`` or ``koch csource``\n" +while : +do + case "$1" in + --extraBuildArgs) + extraBuildArgs=" $2" + shift 2 + ;; + --) # End of all options + shift + break; + ;; + -*) + echo "Error: Unknown option: $1" >&2 + exit 1 + ;; + *) # No more options + break + ;; + esac +done + CC="gcc" LINKER="gcc" -COMP_FLAGS="?{c.ccompiler.flags}" +COMP_FLAGS="?{c.ccompiler.flags}$extraBuildArgs" LINK_FLAGS="?{c.linker.flags}" # add(result, "# platform detection\n") ucpu=`uname -m`