summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim1
-rw-r--r--compiler/evalffi.nim8
-rwxr-xr-xcompiler/evals.nim32
-rwxr-xr-xcompiler/jsgen.nim18
-rwxr-xr-xcompiler/parser.nim47
-rwxr-xr-xcompiler/renderer.nim4
-rwxr-xr-xcompiler/semexprs.nim31
-rwxr-xr-xcompiler/semfold.nim15
-rwxr-xr-xcompiler/semthreads.nim6
-rwxr-xr-xcompiler/trees.nim2
10 files changed, 125 insertions, 39 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 4fa3617d7..5d420c6d2 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -89,6 +89,7 @@ type
                           # formal parameters, var statements, etc.
     nkVarTuple,           # a ``var (a, b) = expr`` construct
     nkPar,                # syntactic (); may be a tuple constructor
+    nkObjConstr,          # object constructor: T(a: 1, b: 2)
     nkCurly,              # syntactic {}
     nkCurlyExpr,          # an expression like a{i}
     nkBracket,            # syntactic []
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index ba6e7ee8f..21a131996 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -142,10 +142,10 @@ proc getField(n: PNode; position: int): PSym =
   else: nil
 
 proc packObject(x: PNode, typ: PType, res: pointer) =
-  InternalAssert x.kind == nkPar
+  InternalAssert x.kind in {nkObjConstr, nkPar}
   # compute the field's offsets:
   discard typ.getSize
-  for i in countup(0, sonsLen(x) - 1):
+  for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
     var it = x.sons[i]
     if it.kind == nkExprColonExpr:
       internalAssert it.sons[0].kind == nkSym
@@ -257,11 +257,11 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
     unpackObjectAdd(x, typ.n, result)
   else:
     result = n
-    if result.kind != nkPar:
+    if result.kind notin {nkObjConstr, nkPar}:
       GlobalError(n.info, "cannot map value from FFI")
     if typ.n.isNil:
       GlobalError(n.info, "cannot unpack unnamed tuple")
-    for i in countup(0, sonsLen(n) - 1):
+    for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
       var it = n.sons[i]
       if it.kind == nkExprColonExpr:
         internalAssert it.sons[0].kind == nkSym
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 3825bbb6c..a05f96829 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -273,9 +273,10 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     result = newNodeIT(nkBracket, info, t)
     for i in countup(0, int(lengthOrd(t)) - 1): 
       addSon(result, getNullValue(elemType(t), info))
-  of tyTuple: 
+  of tyTuple:
+    # XXX nkExprColonExpr is out of fashion ...
     result = newNodeIT(nkPar, info, t)
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       var p = newNodeIT(nkExprColonExpr, info, t.sons[i])
       var field = if t.n != nil: t.n.sons[i].sym else: newSym(
         skField, getIdent(":tmp" & $i), t.owner, info)
@@ -999,10 +1000,10 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
 
   case expandedSym.kind
   of skTemplate:
-    let genSymOwner = if c.tos != nil and c.tos.prc != nil: 
-        c.tos.prc 
-      else:
-        c.module
+    let genSymOwner = if c.tos != nil and c.tos.prc != nil:
+                        c.tos.prc 
+                      else:
+                        c.module
     result = evalTemplate(macroCall, expandedSym, genSymOwner)
   of skMacro:
     # At this point macroCall.sons[0] is nkSym node.
@@ -1342,7 +1343,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
         cc = result
     if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
     else: result = evalOp(m, n, a, b, cc)
-    
+
 proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
   result = emptyNode
   dec(gNestedEvals)
@@ -1385,6 +1386,23 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
         if isSpecial(result): return 
         a.sons[i] = result
     result = a
+  of nkObjConstr:
+    let t = skipTypes(n.typ, abstractInst)
+    var a: PNode
+    if t.kind == tyRef:
+      result = newNodeIT(nkRefTy, n.info, t)
+      a = getNullValue(t.sons[0], n.info)
+      addSon(result, a)
+    else:
+      a = getNullValue(t, n.info)
+      result = a
+    for i in countup(1, sonsLen(n) - 1):
+      let it = n.sons[i]
+      if it.kind == nkExprColonExpr:
+        let value = evalAux(c, it.sons[1], flags)
+        if isSpecial(value): return value
+        a.sons[it.sons[0].sym.position] = value
+      else: return raiseCannotEval(c, n.info)
   of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
   of nkWhileStmt: result = evalWhile(c, n)
   of nkCaseStmt: result = evalCase(c, n)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 94b662b48..64175dc93 100755
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -758,7 +758,7 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
 
 const 
   nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
-    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString, 
+    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString, 
     nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, 
     nkCommand, nkHiddenCallConv, nkCallStrLit}
 
@@ -1367,6 +1367,21 @@ proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) =
     appf(r.res, "Field$1: $2", [i.toRope, a.res])
   r.res.app("}")
 
+proc genObjConstr(p: var TProc, n: PNode, r: var TCompRes) =
+  # XXX inheritance?
+  var a: TCompRes
+  r.res = toRope("{")
+  for i in countup(0, sonsLen(n) - 1):
+    if i > 0: app(r.res, ", ")
+    var it = n.sons[i]
+    InternalAssert it.kind == nkExprColonExpr
+    gen(p, it.sons[1], a)
+    r.com = mergeExpr(r.com, a.com)
+    var f = it.sons[0].sym
+    if f.loc.r == nil: f.loc.r = mangleName(f)
+    appf(r.res, "$1: $2", [f.loc.r, a.res])
+  r.res.app("}")
+
 proc genConv(p: var TProc, n: PNode, r: var TCompRes) = 
   var dest = skipTypes(n.typ, abstractVarRange)
   var src = skipTypes(n.sons[1].typ, abstractVarRange)
@@ -1566,6 +1581,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
   of nkCurly: genSetConstr(p, n, r)
   of nkBracket: genArrayConstr(p, n, r)
   of nkPar: genTupleConstr(p, n, r)
+  of nkObjConstr: genObjConstr(p, n, r)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
   of nkAddr, nkHiddenAddr: genAddr(p, n, r)
   of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
diff --git a/compiler/parser.nim b/compiler/parser.nim
index a2c7f71d2..f820c38db 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -254,15 +254,21 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
   optPar(p)
   eat(p, endToken)
 
-proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode = 
+proc exprColonEqExpr(p: var TParser): PNode =
   var a = parseExpr(p)
-  if p.tok.tokType == tok: 
-    result = newNodeP(kind, p)
+  if p.tok.tokType == tkColon:
+    result = newNodeP(nkExprColonExpr, p)
     getTok(p)
     #optInd(p, result)
     addSon(result, a)
     addSon(result, parseExpr(p))
-  else: 
+  elif p.tok.tokType == tkEquals:
+    result = newNodeP(nkExprEqExpr, p)
+    getTok(p)
+    #optInd(p, result)
+    addSon(result, a)
+    addSon(result, parseExpr(p))
+  else:
     result = a
 
 proc exprList(p: var TParser, endTok: TTokType, result: PNode) = 
@@ -309,14 +315,13 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) =
     optInd(p, a)
   eat(p, endTok)
 
-proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind, 
-                            endTok, sepTok: TTokType, result: PNode) = 
+proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = 
   assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
   getTok(p)
   optInd(p, result)
   while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and
       (p.tok.tokType != tkSad) and (p.tok.tokType != tkInd): 
-    var a = exprColonEqExpr(p, elemKind, sepTok)
+    var a = exprColonEqExpr(p)
     addSon(result, a)
     if p.tok.tokType != tkComma: break 
     getTok(p)
@@ -324,10 +329,10 @@ proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind,
   optPar(p)
   eat(p, endTok)
 
-proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind, 
-                         endTok, sepTok: TTokType): PNode = 
+proc exprColonEqExprList(p: var TParser, kind: TNodeKind, 
+                         endTok: TTokType): PNode = 
   result = newNodeP(kind, p)
-  exprColonEqExprListAux(p, elemKind, endTok, sepTok, result)
+  exprColonEqExprListAux(p, endTok, result)
 
 proc setOrTableConstr(p: var TParser): PNode =
   result = newNodeP(nkCurly, p)
@@ -338,7 +343,7 @@ proc setOrTableConstr(p: var TParser): PNode =
     result.kind = nkTableConstr
   else:
     while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}: 
-      var a = exprColonEqExpr(p, nkExprColonExpr, tkColon)
+      var a = exprColonEqExpr(p)
       if a.kind == nkExprColonExpr: result.kind = nkTableConstr
       addSon(result, a)
       if p.tok.tokType != tkComma: break 
@@ -471,16 +476,15 @@ proc identOrLiteral(p: var TParser): PNode =
   of tkNil: 
     result = newNodeP(nkNilLit, p)
     getTok(p)
-  of tkParLe: 
+  of tkParLe:
     # () constructor
-    result = exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, tkColon)
-  of tkCurlyLe: 
+    result = exprColonEqExprList(p, nkPar, tkParRi)
+  of tkCurlyLe:
     # {} constructor
     result = setOrTableConstr(p)
-  of tkBracketLe: 
+  of tkBracketLe:
     # [] constructor
-    result = exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi, 
-                                 tkColon)
+    result = exprColonEqExprList(p, nkBracket, tkBracketRi)
   of tkCast: 
     result = parseCast(p)
   else:
@@ -496,8 +500,11 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
       var a = result
       result = newNodeP(nkCall, p)
       addSon(result, a)
-      exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
-      parseDoBlocks(p, result)
+      exprColonEqExprListAux(p, tkParRi, result)
+      if result.len > 1 and result.sons[0].kind == nkExprColonExpr:
+        result.kind = nkObjConstr
+      else:
+        parseDoBlocks(p, result)
     of tkDo:
       var a = result
       result = newNodeP(nkCall, p)
@@ -564,7 +571,7 @@ proc parsePragma(p: var TParser): PNode =
   optInd(p, result)
   while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and
       (p.tok.tokType != tkEof) and (p.tok.tokType != tkSad): 
-    var a = exprColonEqExpr(p, nkExprColonExpr, tkColon)
+    var a = exprColonEqExpr(p)
     addSon(result, a)
     if p.tok.tokType == tkComma: 
       getTok(p)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 48a190ec1..b4ef52100 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -367,7 +367,7 @@ proc lsub(n: PNode): int =
     else: result = len(atom(n))
   of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: 
     result = len(atom(n))
-  of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern:
+  of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
     result = lsub(n.sons[0]) + lcomma(n, 1) + 2
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
   of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
@@ -779,7 +779,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkRStrLit: put(g, tkRStrLit, atom(n))
   of nkCharLit: put(g, tkCharLit, atom(n))
   of nkNilLit: put(g, tkNil, atom(n))    # complex expressions
-  of nkCall, nkConv, nkDotCall, nkPattern:
+  of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
     if sonsLen(n) >= 1: gsub(g, n.sons[0])
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 3539424d1..1c95a7452 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1551,6 +1551,36 @@ proc semTuplePositionsConstr(c: PContext, n: PNode): PNode =
     addSonSkipIntLit(typ, n.sons[i].typ)
   result.typ = typ
 
+proc semObjConstr(c: PContext, n: PNode): PNode =
+  var t = semTypeNode(c, n.sons[0], nil)
+  result = n
+  result.typ = t
+  t = skipTypes(t, abstractInst)
+  if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
+  if t.kind != tyObject:
+    localError(n.info, errGenerated, "object constructor needs an object type")
+    return
+  var ids = initIntSet()
+  for i in 1.. <n.len:
+    let it = n.sons[i]
+    if it.kind != nkExprColonExpr or it.sons[0].kind notin {nkSym, nkIdent}:
+      localError(n.info, errNamedExprExpected)
+      break
+    var id: PIdent
+    if it.sons[0].kind == nkIdent: id = it.sons[0].ident
+    else: id = it.sons[0].sym.name
+    if ContainsOrIncl(ids, id.id):
+      localError(it.info, errFieldInitTwice, id.s)
+    var e = semExprWithType(c, it.sons[1])
+    let field = lookupInRecord(t.n, id)
+    if field.isNil:
+      localError(it.info, errUndeclaredFieldX, id.s)
+    else:
+      it.sons[0] = newSymNode(field)
+      e = fitNode(c, field.typ, e)
+    it.sons[1] = e
+    # XXX object field name check for 'case objects' if the kind is static?
+
 proc semStmtListExpr(c: PContext, n: PNode): PNode = 
   result = n
   checkMinSonsLen(n, 1)
@@ -1801,6 +1831,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     of paSingle: result = semExpr(c, n.sons[0], flags)
   of nkCurly: result = semSetConstr(c, n)
   of nkBracket: result = semArrayConstr(c, n)
+  of nkObjConstr: result = semObjConstr(c, n)
   of nkLambdaKinds: result = semLambda(c, n, flags)
   of nkDerefExpr: result = semDeref(c, n)
   of nkAddr: 
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index e46bb0459..e26700e27 100755
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -516,13 +516,13 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
       LocalError(n.info, errIndexOutOfBounds)
   else: nil
   
-proc foldFieldAccess(m: PSym, n: PNode): PNode = 
+proc foldFieldAccess(m: PSym, n: PNode): PNode =
   # a real field access; proc calls have already been transformed
   var x = getConstExpr(m, n.sons[0])
-  if x == nil or x.kind != nkPar: return
+  if x == nil or x.kind notin {nkObjConstr, nkPar}: return
 
   var field = n.sons[1].sym
-  for i in countup(0, sonsLen(x) - 1): 
+  for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
     var it = x.sons[i]
     if it.kind != nkExprColonExpr:
       # lookup per index:
@@ -649,7 +649,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       if a == nil: return nil
       result.sons[i] = a
     incl(result.flags, nfAllConst)
-  of nkPar: 
+  of nkObjConstr:
+    result = copyTree(n)
+    for i in countup(1, sonsLen(n) - 1):
+      var a = getConstExpr(m, n.sons[i].sons[1])
+      if a == nil: return nil
+      result.sons[i].sons[1] = a
+    incl(result.flags, nfAllConst)
+  of nkPar:
     # tuple constructor
     result = copyTree(n)
     if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): 
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index 9fc6a54d9..6f24e1f6d 100755
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -311,6 +311,12 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
     # container construction:
     result = toNil # nothing until later
     for i in 0..n.len-1: aggregateOwner(result, analyse(c, n[i]))
+  of nkObjConstr:
+    if n.typ != nil and containsGarbageCollectedRef(n.typ):
+      result = toMine
+    else:
+      result = toNil # nothing until later
+    for i in 1..n.len-1: aggregateOwner(result, analyse(c, n[i]))
   of nkAddr, nkHiddenAddr:
     var a = lvalueSym(n)
     if a.kind == nkSym:
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 08b89a76e..f371cb021 100755
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -115,7 +115,7 @@ proc isDeepConstExpr*(n: PNode): bool =
     result = true
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
     result = isDeepConstExpr(n.sons[1])
-  of nkCurly, nkBracket, nkPar, nkClosure:
+  of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
     for i in 0 .. <n.len:
       if not isDeepConstExpr(n.sons[i]): return false
     result = true