Generate placeholder code for "mark in.dst".
diff --git a/cmd/puffs-c/internal/cgen/statement.go b/cmd/puffs-c/internal/cgen/statement.go index 4995671..09118fd 100644 --- a/cmd/puffs-c/internal/cgen/statement.go +++ b/cmd/puffs-c/internal/cgen/statement.go
@@ -68,6 +68,10 @@ b.writes(";\n") return nil + case a.KIO: + b.writes("/* placeholder */\n") + return nil + case a.KIf: // TODO: for writeSuspendibles, make sure that we get order of // sub-expression evaluation correct.
diff --git a/doc/puffs-the-language.md b/doc/puffs-the-language.md index 01654a8..6a3975f 100644 --- a/doc/puffs-the-language.md +++ b/doc/puffs-the-language.md
@@ -54,9 +54,10 @@ - `var` -1 keyword deals with I/O: +2 keywords deal with I/O: - `limit` +- `mark` TODO: categorize and, or, not, as, ref, deref, false, true, in, out, this, u8, u16, etc.
diff --git a/gen/c/std/flate.c b/gen/c/std/flate.c index 696e280..457ccc4 100644 --- a/gen/c/std/flate.c +++ b/gen/c/std/flate.c
@@ -831,6 +831,7 @@ switch (coro_susp_point) { PUFFS_BASE__COROUTINE_SUSPENSION_POINT(0); + /* placeholder */ while (true) { PUFFS_BASE__COROUTINE_SUSPENSION_POINT(1); if (a_dst.buf) {
diff --git a/lang/ast/ast.go b/lang/ast/ast.go index 7146313..33ab789 100644 --- a/lang/ast/ast.go +++ b/lang/ast/ast.go
@@ -40,6 +40,7 @@ KField KFile KFunc + KIO KIf KIterate KJump @@ -71,6 +72,7 @@ KField: "KField", KFile: "KFile", KFunc: "KFunc", + KIO: "KIO", KIf: "KIf", KIterate: "KIterate", KJump: "KJump", @@ -133,6 +135,7 @@ func (n *Node) Field() *Field { return (*Field)(n) } func (n *Node) File() *File { return (*File)(n) } func (n *Node) Func() *Func { return (*Func)(n) } +func (n *Node) IO() *IO { return (*IO)(n) } func (n *Node) If() *If { return (*If)(n) } func (n *Node) Iterate() *Iterate { return (*Iterate)(n) } func (n *Node) Jump() *Jump { return (*Jump)(n) } @@ -480,6 +483,27 @@ } } +// IO is "mark LHS": +// - ID0: <IDMark> +// - LHS: <Expr> +// +// TODO: "mark LHS { List2 }"? +// +// TODO: also represent "limit LHS"? +type IO Node + +func (n *IO) Node() *Node { return (*Node)(n) } +func (n *IO) Keyword() t.ID { return n.id0 } +func (n *IO) Value() *Expr { return n.lhs.Expr() } + +func NewIO(keyword t.ID, value *Expr) *IO { + return &IO{ + kind: KIO, + id0: keyword, + lhs: value.Node(), + } +} + // Return is "return LHS", "return error ID1" or "return suspension ID1": // - ID0: <0|IDError|IDSuspension> // - ID1: message
diff --git a/lang/check/bounds.go b/lang/check/bounds.go index 18ff1f3..c517f2d 100644 --- a/lang/check/bounds.go +++ b/lang/check/bounds.go
@@ -241,6 +241,10 @@ _, _, err := q.bcheckExpr(n.Expr(), 0) return err + case a.KIO: + _, _, err := q.bcheckExpr(n.IO().Value(), 0) + return err + case a.KIf: return q.bcheckIf(n.If())
diff --git a/lang/check/type.go b/lang/check/type.go index 38ee599..df4bb09 100644 --- a/lang/check/type.go +++ b/lang/check/type.go
@@ -84,6 +84,18 @@ case a.KExpr: return q.tcheckExpr(n.Expr(), 0) + case a.KIO: + n := n.IO() + val := n.Value() + if err := q.tcheckExpr(val, 0); err != nil { + return err + } + typ := val.MType() + if key := typ.Name().Key(); typ.Decorator() != 0 || (key != t.KeyReader1 && key != t.KeyWriter1) { + return fmt.Errorf("check: %s expression %q, of type %q, does not have an I/O type", + n.Keyword().String(q.tm), val.String(q.tm), typ.String(q.tm)) + } + case a.KIf: for n := n.If(); n != nil; n = n.ElseIf() { cond := n.Condition()
diff --git a/lang/parse/parse.go b/lang/parse/parse.go index ab0ce69..ef29acf 100644 --- a/lang/parse/parse.go +++ b/lang/parse/parse.go
@@ -632,6 +632,14 @@ o, err := p.parseIf() return o.Node(), err + case t.KeyMark: + p.src = p.src[1:] + value, err := p.parseExpr() + if err != nil { + return nil, err + } + return a.NewIO(x, value).Node(), nil + case t.KeyReturn: p.src = p.src[1:] keyword, message, value, err := t.ID(0), t.ID(0), (*a.Expr)(nil), error(nil)
diff --git a/lang/token/list.go b/lang/token/list.go index a11499d..a6c90fc 100644 --- a/lang/token/list.go +++ b/lang/token/list.go
@@ -242,6 +242,7 @@ KeyConst = Key(IDConst >> KeyShift) KeyTry = Key(IDTry >> KeyShift) KeyIterate = Key(IDIterate >> KeyShift) + KeyMark = Key(IDMark >> KeyShift) KeyFalse = Key(IDFalse >> KeyShift) KeyTrue = Key(IDTrue >> KeyShift) @@ -428,6 +429,7 @@ IDConst = ID(0x77<<KeyShift | FlagsOther) IDTry = ID(0x78<<KeyShift | FlagsOther) IDIterate = ID(0x79<<KeyShift | FlagsOther) + IDMark = ID(0x7A<<KeyShift | FlagsOther) IDFalse = ID(0x80<<KeyShift | FlagsLiteral | FlagsImplicitSemicolon) IDTrue = ID(0x81<<KeyShift | FlagsLiteral | FlagsImplicitSemicolon) @@ -630,6 +632,7 @@ KeyConst: {"const", IDConst}, KeyTry: {"try", IDTry}, KeyIterate: {"iterate", IDIterate}, + KeyMark: {"mark", IDMark}, KeyFalse: {"false", IDFalse}, KeyTrue: {"true", IDTrue},
diff --git a/std/flate/decode_flate.puffs b/std/flate/decode_flate.puffs index 2aaec98..427f3f5 100644 --- a/std/flate/decode_flate.puffs +++ b/std/flate/decode_flate.puffs
@@ -116,6 +116,11 @@ ) pub func flate_decoder.decode?(dst writer1, src reader1)() { + // TODO: when is the mark undone? Explicitly or implicitly? Right now, we + // just assume that the mark is dropped at function end, since the arg is a + // writer1 not a *writer1. Should we support nested marks? Should this be + // "mark dst { etc }" that has a block and unmarks at the block end? + mark in.dst while true { var z status = try this.decode_blocks?(dst:in.dst, src:in.src) if not z.is_suspension() {