ifhead -> Newlines if expr block
ifstatement -> ifhead iftail
]]
+
+
+13oct2020 - much later.
+
+ Maybe a different approach to newlines. Never shift them, only use
+ them like indent to guide parsing.
+
+ IN is just recorded
+ OUT must reduce until top symbol contains an IN, which is cancelled.
+
+ Some productions are flagged as $$NEWLINE (or similar) meaning that they can
+ only be reduced as a whole number of lines.
+ When we see a newline, we record that until a non-newline is seen.
+ If we cannot shift and so choose to reduce:
+ if the production doesn't require a newline - we just reduce.
+ If it does, and we have recently seen a newline, again we reduce.
+ Otherwise, we signal an error and (maybe) shift until we see a newline.
+ NOTE the newline only counts if there are no indents.
+
+ This means that
+ a = b
+ + c
+
+ would be parsed as a statement, which I don't want.
+ But I do want
+ if foo: bar
+ else: baz
+
+ to be a single statement.
+ So a new line in some context must force a reduction, like OUT.
+ When exactly does a newline force?
+ An OUT forces a reduction until the top symbol has the matching indent.
+ A NEWLINE ?? Must depend on the grammar.
+
+
+
+ Q: Can this be only about resolving ambiguity and reporting errors?
+ If the default is to shift if we can, reduce otherwise, then
+ 2D causing an early reduce can resolve ambiguity.
+
+ If certain productions must end at EOL, and error is thrown if they don't.
+
+ That latter really must be a gramatically need to shift a newline.
+
+ Maybe I'm wrong about reporting errors. Maybe they should always come from
+ a failure to shift or reduce.
+
+ One of my problems was
+ if foo: if bar: dostuff
+ where the newline at the end needs to reduce everything, so I can
+ require at most one newline in the grammar.
+ It probably should be required for the first 'if'
+
+ Stmt -> if Cond : StLstNL
+ StLstNL -> StLst NL
+
+ StLst -> Stmt
+ | StLst ; Stmt
+ | SlLst NLs Stmt
+ | NLs StLst
+
+ IfSt -> IfHead
+
+
+ NONO. I don't want some statements that end with NL and some that don't.
+
+ - Record indent with preceding token and line-start with following
+ - when reducing all indents are accumulated into the new symbol,
+ and the line-start of first symbol is preserved. Other line-starts are dropped
+ - When OUT in lookahead, there is an indent within 'min_prefix' of top state,
+ decrement closest indent count and discard the OUT
+ - When OUT in lookahead and cannot be discarded and top state can be reduced,
+ reduce it
+ - When OUT canot be discarded or reduce, and error is triggered.
+ - No production can be reduced if it contains unmatched indents. If cannot shift,
+ then error.
+ - Some productions are marked as $LINE
+ - any state that contains an item at the start of a $LINE is marked 'starts line'
+ - if there is an indent more recent than a starts-line state, or the top
+ state starts_Line, newlines are ignored.
+ - if a newline is seen but not ignored, and the top state can be reduced,
+ it is reduced.
+ - A $LINE production can only be reduced by a newline, or, if it didn't start
+ at start-of-line, by an OUT
+
+ so
+ Block -> : statementlist $LINE
+
+ I want to be sure that
+ if cond {
+ statements
+ } else {
+ more
+ }
+
+ is OK. Here the "IfHead" doesn't end on a newline, but the state that is
+ expecting 'Block' 'starts-line'. I guess as "Block -> { statementslist }"
+ isn't a $LINE, it can be reduced by 'else'.
+
+24oct2020
+
+ Maybe I don't want TK_out to force a reduce (mostly). Maybe the grammar
+ should be in control. So when we see an OUT we record it off-stack.
+ If we reduce for some other REASON and the top state contains an indent,
+ we cancel.
+ When we decide to SHIFT, if the top of stack has -ve indent, that is an
+ error.
+ So with C,
+ if (cond) {
+ s1;
+ s2;
+ s2;
+
+ would show an error when s2 was shifted.
+ if (cond)
+ s1;
+ s2;
+ needs to show an error too. The "if(Cond)s1;" statement would have an
+ internal indent.
+
+ So maybe the requirement is that no symbol has unbalanced internal
+ indents.
+ When we shift we require that top balances first.
+ So we count up outs and ins. There can be several OUTs and at most on
+ IN before a terminal.
+ If the terminal can be shifted, the top symbol must have no internal
+ indents after cancelling with out, and there must be no outstanding
+ TK_outs
+ If the terminal cannot be shifted we reduce and we must have enough
+ outs to balance anything within the reduction.
+
+ So indents on the stack are always between symbols. Each frame has
+ a symbol, the indent after it etc.
+
+ If we don't have enough outs to complete a reduction we raise an error
+ and need to discard (or shift/reduce) until we find an 'out'.
+ If there are too many outs to shift we again need an error which will
+ hopefully let us reduce and cancel some outs - just discarding states
+ will help with that.
+
+ So: outs must cancel, following token must envourage reductions
+
+ Some productions end with newline, their start state is 'starts-line',
+ and if there is an indent since a starts-line, we ignore newlines.
+
+ If we don't ignore newlines, then there is a starts-line state that we
+ should reduce to. If we don't have enough symbols yet, we error.
+ So if we see a newline, we reduce until the newline would be ignored.
+
+ If that state expects a newline and we don't have one, we error.
+ Except.. I sometimes want OUT to work like a newline.
+ If I need a newline and reduction isn't to start of line
+
+ If state expects newline and we don't have one but do have OUTs
+ we reduce as long as there are enough outs and raise an error if
+ we end up at start of line.
+
+
+ Do I want to require that a newline be shifted? We can synthesize
+ one when minprefix is less than since newline and we have an out.
+
+
+ Summary of stuff.
+ A shift requires there be no pending OUT ??
+ A reduce requires there be no pending indent, i.e that
+ indents within the reduction don't exceed outs.
+ NO this doesn't work.
+ A IN increments the indent on the top frame - never causes error
+ An OUT decrements indent in a frame within min_prefix, or error
+ A NEWLINE is either ignored or shifted, but is duplicated when
+ shifted.
+ After an OUT is handled, if a NEWLINE is expected but will only
+ reduce a partial line, it is provided.
+
+ if foo: if bar:
+ stuff
+ bazz
+
+ This effectively pretends there was a IN at the start of the "line",
+ and we are not doing two OUTs with a NEWLINE between.
+ if foo:
+ if bar:
+ stuff
+ baz
+
+
+ Do I really want to shift newlines:
+ yes: simpler grammer
+ no: don't need to record min-prefix.
+
+ I think 'yes'.
+
+ So discard $NEWLINE
+ Place NEWLINE in the grammar
+ When completing a state, if any production contains NEWLINE, record as
+ StartsLine
+
+
+ ---
+ My idea of ignoring newline when the top state is a starts_line state isn't
+ working.
+ The idea was that reducing
+ statement -> assignment NEWLINE
+ would leave at a starts_line start, so NEWLINEs would be ignored.
+ But this leaves us at a ' ... statement . ' state
+ e.g. " Statementlist -> Statement . "
+ which reduces to "Statementlist -> Statementlist . Statement"
+
+
+
+30oct2020
+
+ Review: because it isn't working (as usual).
+
+ Indenting have 2 effects:
+ - it triggers errors when something looks wrong
+ - it causes newlines to be sometimes ignored.
+
+ Specifically:
+ - A symbol that starts indented must finish while still indented.
+ So an OUT cannot cancel an IN except in the top phrase, and an attempt to
+ shift while there are pending OUTs is an error.
+ - A symbol that begins at the start of line and contains an indent may only
+ be the top symbol - shifting before an OUT cancels the indent is an error.
+
+ - Newlines are ignored when there is an indent since a starts-line state
+
+ Procedurally:
+ - There can be one IN and several OUTs pending - we update the counters
+ as they are seen.
+ - If there are pending OUTs and their is an indent in the top phrase,
+ we can cancel an indent.
+ - a SHIFT becomes an error if the top symbol has an indent and started
+ at beginning of line
+ - a SHIFT becomes an error if there are pending OUTs
+ - a SHIFT that is not an error first imposes the IN on the top of stack
+ - REDUCE may happen at any time.
+
+ Newlines, when not ignored, are repeating terminals. An indefinite series
+ is generated until a state is reached where they are ignored.
+ The expectation is that they will be shifted (possibly after some reductions)
+ and then a reduction will happen which changes the state appropriately.
+
+ It is vital that no recursive production keeps consuming newlines
+ foo -> foo NEWLINE
+ as that will be fed indefinitely, or if newlines are ignored, will never reduce.
+
+ NEWLINEs are recognized if there is a starts_line state since the most recent
+ indent, but not when the current state is starts_line. So once we reach
+ starts_line, we ignore newlines until something else is shifted.
+ Or maybe only a starts_line state at the start of a line?
+
+ A starts_line state has an item "head -> . stuff NEWLINE"
+ So if were just reduce 'foo -> foo NEWLINE' then we are at the end of foo,
+ so an earlier state with have ".foo" and so "foo -> . foo NEWLINE" and so will
+ be starts_line. So we will always accept a NEWLINE. So these must be disallowed.
+
+ How does "if cond : if cond : print NEWLINE" parse?
+ "block -> : slist NEWLINE"
+ "slist -> statment | slist statement"
+ "statement -> print NEWLINE | if cond block NEWLINE"
+
+ so starts_line are before statement or ':' - I don't want that as it would allow a newline
+ before ':' to be ignored.
+ Maybe I want starts AFTER a NEWLINE?? Did I do that before?
+ So after block, after statement, after slist.. but we expect NEWLINE there.
+
+ Maybe the important states are "foo -> baz . stuff NEWLINE".
+ Once we've entered a path to a NEWLINE, we need to be ready for it.
+ So: after :, after print after if and cond and block
+
+ The repeating newlines are hurting now. The rule to start ignoring them
+ isn't working.
+ ifhead else if expr : statementlist [NEWLINE]
+ the NEWLINE should be ignored.
+ There is an indent after ':' but final state is startsline because this could
+ be the end of a block -> : statementlist NEWLINE
+ But I want that newline to be ignored because of the indent.
+
+ if (A)
+ b;
+ c;
+ why is that bad? How can we know? Because we reduce to start-of-line
+ and still have an indent.
+
+ a =
+ b + c
+ + d
+ *
+
+ I need some good examples to remind myself.
+ Why do I want min_prefix? I allow indents to be cancels within min_prefix
+ cmd -> { statements }
+
+
+01nov2020
+ ARRRGGHHH I keep going down rabbit holes. I need to take a more mathematical
+ approach and present clearly what I have and what I need.
+ The big issue, for the moment at least, is when to ignore newlines.
+ I REALLY like the idea of newlines being repeating until they are ignored.
+ I definitely like that they are ignored after an indent unless they are explicitly
+ expected. I need to ensure they are not expected at awkward places, like the
+ start of a line.
+
+ I want to be careful of making LL assumptions about the LR grammar. i.e. I cannot
+ assume the end from the beginning - that is was LL does. I want the appearance
+ of a newline to only make a difference once it appears. But at the point that
+ it appears we need to know if it is to be ignored. In
+ a = b + NEWLINE
+ it isn't ignored event though it isn't expected exactly here. In
+ a = b + (IN)
+ c + NEWLINE
+ it is ignored and the difference is that no state since the IN expects a
+ newline.
+
+ To acknowledge LR approach we need to take the latest state. The start of
+ line, before the 'a' is tempting but we hardly know anything there. After the 'a'
+ is tempting, but that would mean after a[b+c].thing(foo) as well which seems to
+ miss the point.
+ Maybe something earlier sets the expectation?
+ if cond :
+ The ':' says newline-separated things are coming. So it is the state
+ after the ':' which says 'newlines matter'. This will be after the indent.
+ So if we saw
+ if cond {
+ then maybe newlines don't matter (depending on grammar)
+
+ But a newline is ignored *at* that state, so that blank lines can be skipped.
+ I think there is a 'statementlist' symbol and at the start or end of that symbol
+ newlines are ignored. Within that symbol unindented newlines are significant.
+ statementlist -> statement NEWLINE
+ | statementlist statement NEWLINE
+
+
+02nov2020
+ Can I drop the 'min-prefix' concept?
+ The means that OUT can only cancel against an indent 'in' or immediately before
+ the top symbol. This means we go back to keeping a 'starts_indented' flag and
+ storing each indent with the following symbol.
+
+ Then the 'ignore newline' test is since_starts_line > since_indent
+ but since_indent is 0 fir there are internal indents and 1 if there is only a
+ starts_indented indent.
+
+ So a TK_in simply sets starts_indented for next
+ TK_out is recorded
+ Whenever top symbol has indents and outs are recorded, we cancel.
+ If we want to shift with pending outs, that causes an error
+
+ I need a reason to signal an error for
+ if (a)
+ b=1;
+ c=1;
+ based on indents. equally for
+ if (c)
+ b=1;c=1;
+ If indent is a continuation, then 'c=1;' but be part of 'if...' before
+ it is part of what comes before?
+ This means the OUT will not be able to see the IN ... unless the whole
+ statement list ends here....
+ In "a = IN b + c ; " the ';' causes a reduction to Assignment with indent
+ so I must be happy for the 'c=' to reduce to 'ifstatement' with an indent,
+ but reducing to the recursive 'statementlist' seems wrong. Maybe these
+ left-recursive productions really are special.
+ But what about 'expr -> expr + expr' ??
+
+ The rule I'm depending on is that I cannot shift with a pending OUT.
+ So everything since the IN needs to compress to a single symbol.
+ If the code is
+ {
+ if (a)
+ b=1;c=1;
+ }
+ then the '}' will reduce to "{ statementlist" before shifting, so the OUT will be
+ cancelled. The question is: how can we prevent that in the grammar?
+ There are 2 OUTs (in this case) does that help?
+ A comparable case is
+ {
+ foo;
+ if (a)
+ b=1;c=1;
+ }
+ In that case the two OUTs will be cancelled at clearly different times, but not real
+ difference.
+
+ {
+ foo;
+ if (a)
+ b=1;c=1;
+ bar;
+ }
+
+ Now the 'bar' will be blocked from shifting.... no it won't.
+
+ I need a new rule - this *must* be wrong, even when we ignore newlines.
+ But why? Because "b=1;c=1;" looks like a statementlist, but isn't.
+ It isn't because a statementlist doesn't belong here, ony a block or a statement.
+ How do I know that indent is continuing the 'if', not the statementlist.
+ I need some marking on statementlist to say "Cannot be continued by indent"
+ I guess that is what NEWLINE is for.
+
+ So the rules would be "a suitably marked production cannot be reduced with
+ outstanding indents. If nothing can be shifted, an error must be raised.
+ These will typically be productions that end in a NEWLINE, but maybe any
+ production from a symbol that can produce a NEWLINE, or that is marked $$something
+
+ Back to TK_newline. These are duplicated on shift, but discarded when not wanted.
+ They are not wanted unless there is a starts-line start below the current state,
+ and more recent than the most recent indent.
+ A starts-line state is any state which contains an item with a NEWLINE and dot
+ at the start.
+
+ statementlist -> statement NEWLINE
+ | statementlist statement NEWLINE
+
+
+ Q: how do nested 'if's resolve?
+ if cond:
+ if cond2:
+ print
+ else:
+ die
+
+ statement -> if cond block
+ | if cond block else block
+
+ The tokenization would be
+ if cond : IN if cond2 : IN print NL OUT NL OUT IN else : IN die NL OUT NL OUT NL
+ 1 2 A 2 B 1 3 4 C 4 D 3 E
+ so NLs:
+ A makes 'print' a statment,
+ B makes 'if cond2' a statment,
+ C makes 'die' a statement
+ D is protected by IN/3 and is ignored.
+ E makes if cond .. else.. a statement
+
+ What if I also had
+
+ | if cond block NEWLINE else block
+
+ Then on seeing the NEWLINE I wouldn't know whether to shift it,
+ or reduce to a statement.
+ To fix that I would need:
+ statementlist -> statement | statementlist statement
+ statement -> simplestatements NEWLINE
+ | if cond block NEWLINE
+ | if cond block else block NEWLINE
+ | if cond block else statement
+ | if cond block NEWLINE else block
+ | if cond block NEWLINE else statement
+
+ But wait.... Allowing NEWLINE before 'else' confuses the parse of 'if cond:...' above.
+ NL-B makes "if cond block NEWLINE" and then the else can be shifted, but that is illegal
+ because of the negative indent. That means the negative indent must prevent SHIFT.
+
+
+ Do I still need to know which symbols are 'line-like' ??
+ Yes, to make it easier to detect line-line productions which must contain unmatched indents.
+ Do I need recursive line-like detection?
+ For no-indent productions, it probably makes sense.
+ For starts-line detection? I don't think so. 'block' isn't the start of a line.
+ And not really needed for no-indent
+
+
+ Do I need to worry about left-recursive symbols?
+ I don't think so. There should always be some terminal - often NEWLINE -
+ which will ensure the symbol isn't extended??.. or if it did we would get
+ a parse error due to uncancelled OUT
+
+ Do I need to split indents?
+ A stack frame holds "symbol state". Indents are within or before the symbol.
+ For cancelling with OUT, indents within and before the top state are equivalent.
+ For hiding newlines the indent before the symbol is too distant. f->next_indented ? "/" : "",
+
+ So: yes.
+ Should I store them in the stack?
+ "symbol+indents indent state"
+ So when we see an indent, we mini-push that
+ Any indent since state protects newline
+ Out can be cancelled if top state has indents, or previous has trailing indent.
+
+ Rather than an ignore_newline flag we need a outs_needed flag. This is how
+ many outs are needed before we process newlines.
+ If state is startsline, then outs_needed == infinity.
+ Else it is a count of indents since a starts-line state.
+ So maybe it is an indents_since_starts_line and we test state and indents.
+
+ So:
+ 1/ rearrange frame to include 'indented' in the top frame
+ 2/ replace ignore_newline with indents_on_line
+
+14nov2020
+ I'm getting close...
+ Problem is correctly ignoring of newlines.
+ I ignore them after an indent - that bit is easy.
+ But I also ignore them at a start-line symbol - sometimes.
+
+ INDENT statementlist NEWLINE should ignore the newline
+ but
+ INDENT statementlist if expr : stl if expr : stl NEWLINE should not
+
+ (/0s) Statementlist (11s) IfHead (5) else (22) if (3) Expression (19) : (29s) Statementlist (40s) [NEWLINE:22:0] - Ignore
+
+ This shouldn't Ignore. Is that because there is a non-'s' since the '/' ??
+
+ i.e Ignore newlines if all states since indent are startsline, or if none are.
+ Don't count current state if it is startsline
+ indents_on_line > outs || all_startsline(...)
+
+ No - better, but no banana. if expr { statement; newline
+ need to ignore even without the indent.
+ So I need a new type of state - one that is at the start of Statementlist but
+ not at the end. State 29 in the above, but not 40
+
+(/0s) Statementlist (11s) if (3) Expression (19) { (30s) Statementlist (39s) [NEWLINE:34:0] - ERROR
+
+18nov2020
+ So:
+ I introduce "startsline" and "endsline" states.
+ A state before a linelike symbol is startsline, a state after such a
+ symbol is endsline. A state can be both, in which case we consider it 'endsline'.
+ So 11 endsline, 30 startsline 39 endsline
+
+ If there is an indent since the last startsline or endsline state, we ignore NEWLINE.
+ If there are only start/end line states since indent, ignore newline
+ if there are only endsline states since startsline, ignore newline - NO.
+
+
+ I wonder if maybe I should have IN and OUT in the grammar.
+ The tokens can still appear anywhere, but the production can only be reduced of there is an IN there.
+ Block -> : IN Statementlist OUT | : SimpleStatements
+ might get messy. But it already is messy.
+
+20jan2021
+ Where am I?
+ The big questions seems to be: when can/must I ignore NEWLINEs?
+ Conversely when do they REDUCE or get SHIFTed?
+ The answer must lie in what appears between the most recent INDENT and the NEWLINE.
+ - if there are no startsline states, we can ignore.
+
+ It seems that I need to be able to see the start of a block, either an indent, or a {..
+ But if there is a statementlist, surely a block started? No, that misses a point.
+ INDENT ignores newlines because there will be a matching OUT
+ Maybe { causes NEWLINEs to be ignored because there is a matching } expected?
+
+ If a startesline state is at the end of a productions, it plays no role in NEWLINEs,
+ but if it is followed by something
+
+23jan2021
+ review/summary.
+ We track indents and newlines. The goal is resolve ambiguities and detect errors.
+ Ambiguities are resolved by forcing a REDUCE in some circumstances when an OUT or NEWLINE is seen.
+ Errors happen when an there are too many OUTs.
+ NEWLINEs are a normal part of a grammar, except that they get ignored sometimes when they are not relevant.
+ and are protected.
+
+ 1/ a production from a lineline symbol cannot be reduced while it contains an unbalanced indent,
+ and so must be reduced before an excess OUT token is processed.
+ 2/ NEWLINES are ignored if there is an IN since a start-of-line state
+
+ Otherwise NEWLINEs must be in the grammar. This can be awkward where they are optional
+ such as before an 'else'. To handle the fact that a structured statement can be multiple lines
+ or few we need to build it up from the possible line-like parts.
+ Maybe this means that ifpart, elsepart, whilepart, casepart etc need to be statements which
+ are combined above the grammar level??
+ The reason has something to do with reducing to Statement when the newline is shifted.
+ I wonder if that is really needed.
+ if we have "ifpart -> if cond block" then that can be followed by elsepart, but we
+ need a separate "ifpartNL -> ifpart NEWLINE | ifpartNL NEWLINE" which can also be followed
+ by an elsepart, or can reduce to a statement
+ ..but no. That isn't sufficient if NEWLINEs are indefinitely duplicated.
+ So if we don't ignore newlines where they aren't needed, we cannot duplicate them.
+
+ The need for duplicating was constructs like
+ if cond : if cond2 : action
+ which needed 2 NEWLINEs, one for each statement.
+ Maybe the "if cond2 : action" needs to be a simplestatement.
+ When we see the NEWLINE we can (must?) reduce anything that started since
+ a start-of-line, which creates the simplestatement.
+
+ So let's try dropping the infinite repeat and require newlines in the grammar
+
+ Extra rules:
+ - a production from lineline symbol cannot be reduced while it contains unbalanced
+ indent
+ - a NEWLINE is ignored if no startsline state since indent
+ - a NEWLINE cannot be shifted unless top startsline is at start of line.
+
+ So a NEWLINE is:
+ - ignored if not startsline since indent
+ - forces REDUCE if top startsline is not at start of line !!!!. i.e. don't shift
+ - else can be SHIFTed.
+
+26jan2021 - happy australia/invasion day
+ I want ": simplestatements" to be a valid block, but not when there is an
+ indent in the middle
+ Previously this was resolved by having an SSLine -> simplestatements NEWLINE
+ and the SHIFT of the NEWLINE outweights the reduction to block.
+ And I have that now with Statement -> SimpleStatements NEWLINE...
+ Ahh.. it is because I put Newlines before Statementlist. I guess a NEWLINE
+ needs to be a Statement
+
+ I currently suppress shift unless "outs == 0". That means
+ if cond:
+ statement
+ else:
+ doesn't shift the 'else' because the "out" isn't resolved.
+ Without the leading space, the NEWLINE reduces to ifstatement, and I sort-of know
+ that is an issue.
+ So: why suppress SHIFT when there is an outstanding OUT... or better Question,
+ why is this OUT still outstanding?
+ Ahhh.. I misunderstood. I DO want to reduce that 'if' because it is nested.
+ I have an IfStatement what needs to reduce to a Statement and merge with a
+ Statementlist, so the OUT can be cancelled and then the 'else' shifted.
+ BUT as 'else' is the lookahead.... I need NEWLINE to reduce IfStatement to
+ Statement. But even with a NEWLINE we don't SHIFT that because we still have
+ that OUT to clear. So how do I clear an OUT ?? It can only be cancelled when
+ the matching IN reaches TOS, which requires the NEWLINE to be shifted.
+ We cannot shift the newline early, partly because that would be wrong, and
+ partly because it gets reduced to a statement and disappears.
+
+ Hmmm. After blocking SHIFT(NL) when we don't have a line I see
+ progress but not there yet.
+ if false {
+ print = OK
+ } else {
+
+ After the OK is NL OUT NL
+ The first NL is shifted and reduces down to Statementlist and the OUT cancels.
+ But now the NL doesn't belong. Can I explicitly allow NL before } ??
+ No, because it doesn't even SHIFT. It cannot because the Statementlist doesn't
+ appear to be sol - the OUT hide that and it now looks like
+ if expr { statementlist
+
+ Arggh. I think I need to hide the starts-line state in this context.
+ More thinking needed.
+
+ I introduced the shift-block to make sure the NEWLINE paired with the right line.
+ Here the NEWLINE should probably be ignored. But why? It isn't indented, but it
+ is inside a multiline thingy.
+ Might be better to explicitly allow it and find some way to let it be SHIFTed.
+ Problem is that the Statementlist is linelike, but I don't want that here.
+ Hard to avoid when the statements are and must be linelike.
+ Maybe I need a way to hide linelike-ness.
+
+ Maybe a state should only be startline if the core item has dot followed by
+ a single symbol (which can derive a newline) ??