diff options
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/src/parse.cff b/src/parse.cff index dbc8e29..ffe9a9d 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -827,6 +827,15 @@ fn findaggfield(ty *const Type, name *const u8) *AggField { return #null; } +fn findbitffield(ty *const Type, name *const u8) *BitFField { + foreach_ptr(fld, i, ty.u.BitF.flds) { + if streq(fld.name, name) { + return fld; + } + } + return #null; +} + fn parsebitfield(P *Parser, name *const u8) *const Type { let ty Type = { .u: :BitF{} }; let bitf = &ty.u.BitF; @@ -1246,6 +1255,43 @@ fn parsearrini(P *Parser, loc Loc, ty *const Type) Expr { return { loc, ty, :ArrIni { idxs->move(P.alloc), exs->move(P.alloc), maxn }}; } +fn parsebitfini(P *Parser, loc Loc, ty *const Type) Expr { + let loc = loc; + let tok Tok #?; + let flds Vec<*const BitFField> = {}; + let exs Vec<Expr> = {}; + let iota = 0u64; + while !lexmatch(P, &tok, '}') { + let fld *BitFField #?; + let ex Expr #?; + if lexmatch(P, &tok, '.') { + fld = findbitffield(ty, (tok = lexexpects(P, :ident, "field name")).u.ident); + lexexpect(P, ':'); + if fld == #null { + fatal(P, tok.loc, "%t has no such field %qT", ty, &tok); + } + iota = (fld - ty.u.BitF.flds.#ptr) + 1; + } else { + if iota >= ty.u.BitF.flds.#len { + fatal(P, tok.loc, "excess elements in %t struct initializer", ty); + } + fld = &ty.u.BitF.flds[iota++]; + } + P.targty = fld.ty; + ex = parseexpr(P); + if !typematchestarg(fld.ty, ex.ty) { + err(P, ex.loc, "incompatible element `%s' type in %t initializer (%t, expected %t)", + fld.name, ty, ex.ty, fld.ty); + } + flds->push(fld); + exs->push(ex); + if !lexmatch(P, &tok, ',') { + lexexpects(P, '}', "`,' or `}'"); + break; + } + } + return { loc, ty, :BitFIni { flds->move(P.alloc), exs->move(P.alloc) }}; +} fn mergetoktrees(alloc *Allocator, src *[#]Tok, n int) [#]Tok { let total = 0z; @@ -1412,7 +1458,7 @@ fn pexprimary(P *Parser) Expr { fatal(P, tok.loc, "%t has no such decl %qT", ty, &tok); } continue; - } else if !ty->is(:Agg) and !ty->is(:Enum) { + } else if !ty->is(:Agg) and !ty->is(:Enum) and !ty->is(:BitF) { fatal(P, tok.loc, "type is not aggregate or enum"); } else {; P.targty = ty; @@ -1500,7 +1546,7 @@ fn pexprimary(P *Parser) Expr { let off = 0z; for ;; { let name = (tok = lexexpect(P, :ident)).u.ident; - let fld = findaggfield(ty, name); + let fld *AggField = ty->is(:Agg) ? findaggfield(ty, name) : #null; if fld == #null { fatal(P, tok.loc, "%t has no such field %qT", ty, &tok); } @@ -1585,6 +1631,8 @@ fn pexprimary(P *Parser) Expr { ex = parseaggini(P, tok.loc, ty); } else if ty->is(:Arr) { ex = parsearrini(P, tok.loc, ty); + } else if ty->is(:BitF) { + ex = parsebitfini(P, tok.loc, ty); } else { fatal(P, tok.loc, "excess elements in initializer"); } |