NeilBrown [Sat, 18 Dec 2021 02:47:45 +0000 (13:47 +1100)]
oceani: add transparent AddressOf operator for function parameters.
If a function parameters is a declared as an reference, and the passed
argument is not, then we insert the new AddressOf operator so that
the correct value is passed.
This allow "var" parameters much like Pascal - though with completely
different syntax.
NeilBrown [Fri, 17 Dec 2021 05:01:11 +0000 (16:01 +1100)]
oceani: add type entry for new structs early.
When a 'struct foo' declaration is found, add the type when 'foo' is
seen rather than when the whole declaration is seen.
This keeps the order of types stable
NeilBrown [Fri, 17 Dec 2021 04:20:54 +0000 (15:20 +1100)]
oceani: propagate_type should return the found type, not what it was compatible with
If the type we have is different from the type expected, but they are
compatible, propagate_type() should return the type that we have.
Otherwise we lose information - which may later be useful.
NeilBrown [Mon, 13 Dec 2021 22:34:25 +0000 (09:34 +1100)]
oceani: change labels to look like enum values, not variables.
A label now looks like ".foo". This makes it a completely separate
namespace from variables.
When we introduce enums, the values will also look like ".foo" an we
know which enum is intended based on context.
Each switch/while will potentially create a local enum type for the
labels.
NeilBrown [Mon, 6 Dec 2021 05:54:07 +0000 (16:54 +1100)]
oceani: add reference type
@foo is a type which is a reference to type 'foo'.
If var is an @foo, then var@ is the foo.
@new() returns an appropriate new object
@free= thing will free thing
@nil is an invalid reference of any type.
NeilBrown [Sat, 4 Dec 2021 23:34:58 +0000 (10:34 +1100)]
oceani: allow types to be used before declaration
As we prepare all types after parsing, we can now use a type before it
is declared.
We need to be careful of mutually recursive structures, and
we need to retry prepare_type if it fails because a needed
member hasn't been prepared yet.
NeilBrown [Sat, 4 Dec 2021 22:37:00 +0000 (09:37 +1100)]
oceani: allow global constants to be used before declared.
When an undeclared name is used, it gets allocated a Tnone variable.
If one of these is found in a 'use' statement, it is assumed to be
a label (that will change later).
If it gets declared as a constant, its type gets set appropriately.
When evaluating global constants, if a value cannot be determined, we
continue with other constants, then, retry. If the failure was because
some constant was not yet declared, this will eventually resolved.
If resolution is not possible, an error is produced.
Currently, non-global variables and functions cannot resolve.
This is tracking in the new Enoconst prop_err flag.
NeilBrown [Sat, 4 Dec 2021 22:29:23 +0000 (09:29 +1100)]
ocean: propagate_types: only set Efail on local err.
propagate_types() currently sets Efail if there has been any parse error
at all. This is wrong.
Instead, keep a count of errors, and only set Efail if that count has increased.
NeilBrown [Sat, 4 Dec 2021 22:13:51 +0000 (09:13 +1100)]
oceani: change the 'ok' flag to 'perr' with well defined bits.
I'll want to extend the information gathered by propagate_types() to
report if a value can be computed immediately. So generalize
'ok' (which contains a magic value) to a set of flags that can be
reported.
NeilBrown [Fri, 3 Dec 2021 07:58:43 +0000 (18:58 +1100)]
oceani: use more precision when printing numbers
I really want constants to be reproduced accurately when printing a
program.
Maybe I should detect and store the precision used, but for now, just
use a larger precision.
NeilBrown [Sat, 20 Nov 2021 05:37:04 +0000 (16:37 +1100)]
oceani: change SimpleStatement to be $*exec, not $*binode
All current SimpleStatements are binode, but future ones may not be.
So change to $*exec.
Declare a binode '*b' in 'reduce' header so the variable is
always available.
NeilBrown [Sat, 20 Nov 2021 00:50:55 +0000 (11:50 +1100)]
oceani: record if a variable declaration was given an explicit type
The type may be determined at the same place as the declaration, yet
still not be explicit. To ensure correct output when printing code,
record what was found.
NeilBrown [Sat, 20 Nov 2021 00:37:52 +0000 (11:37 +1100)]
parsergen: avoid creating extra line in code blocks.
When performing coverage analysis, it is important that the line numbers
seen in the .c file are fairly accurate.
Currently we a lines to the end of a code block, and they appear to have
line numbers that correspond to whatever appears after the code block.
This is confusing.
So put all that extra code on the last line (matching the }$).
Also switch back to "gen_reduce" immediately after the code block.
NeilBrown [Fri, 19 Nov 2021 22:10:36 +0000 (09:10 +1100)]
oceani: improve construction of per-function stack frame
The stack-frame management was confused - not properly transitioned from
a single function to multiple functions.
Now we pass in the function to be processed, and it has a known list of
variables that were in-scope in that function.
We track when each variable went into or out-of scope, sort them, and
re-use frame space for variables which have already gone out-of-scope.
NeilBrown [Mon, 15 Nov 2021 21:23:06 +0000 (08:23 +1100)]
oceani: pass a destination buffer into interp_exec to receive large result.
To handle assignment from large objects - particularly a structure
returned by a function - we cannot just pass back a 'struct value'.
Instead we need to pass in a sufficiently large buffer, and have
the value producer copy into it.
This patch passes in a 'dest' and 'dtype' for this purpose. It is not
yet used to full potential.
NeilBrown [Sun, 14 Nov 2021 05:07:15 +0000 (16:07 +1100)]
parsergen: add action tables when needed.
In most cases there is at most one reducible production per state, and
that is all we previously handled.
However occasionally it can be useful to have more than one, triggered
by different look-ahead symbols.
With this patch, we add entries to the go_to table in that case. The
go_to table now has a flag to indicate if the symbol maps to a state (in
which case it can be SHIFTed if a terminal), or to a production (in
which case it triggers a reduction).
If the in-state production has the special value MANY_REDUCIBLE, when
the parser performs a lookup to see which production, if any, should be
reduced.
NeilBrown [Sat, 13 Nov 2021 08:25:23 +0000 (19:25 +1100)]
parsergen: store reduction information separate from states.
There are more states than reductions (aka productions) so storing the
reduction data in the state table results in a lot of duplication - and
wasted space as some states have no reduction.
So create a separate table of reduction information. This will also
make it easier to allow a state to have multiple reductions with LALR
and canonical-LR grammars.
NeilBrown [Wed, 10 Nov 2021 10:27:50 +0000 (21:27 +1100)]
oceani: remove the need for 'then' in function declarations.
Previously an IN had to follow a terminal because it would never for a
reduce.
This made is a problem for
func FuncName
arguments
do
code
as the IN follows FuncName - a non-terminal.
Fix this by allowing an IN to force a reduce if nothing at all can be
shifted.
After "func IDENTIFIER", nothing can be shifted. The IDENTIFIER must be
reduced to FuncName. At that point, the IN is expected, so it won't be
ignored.
NeilBrown [Sun, 7 Nov 2021 21:21:30 +0000 (08:21 +1100)]
oceani: Add functions
As yet, functions cannot return a value, but they can be passed
parameters.
They are declared a bit like consts, but there isn't a common
header for multiple constants.
A pointer to the body of the function is stored in the 'global' area,
like the vale of any other constant.
Functions can be called as a statement - providing they don't return
anything - or as an expression, which will currently be a type error as
they cannot return the correct type.
We allocate a new 'local' frame for each function call, and free it when
the function completes.
NeilBrown [Tue, 9 Nov 2021 05:05:50 +0000 (16:05 +1100)]
mark-tested: don't fail if coverage is too low
As the whole point of mark-tested is to help improve coverage, it is
silly to rail if coverage is too low.
So make it possible to easily skip that test in the Makefile.
NeilBrown [Tue, 9 Nov 2021 04:58:50 +0000 (15:58 +1100)]
oceani: improve reporting of variables being freed at end of block.
1/ if frame_pos hasn't been set, possibly because type propagation hit
an error, don't report the offset.
2/ Don't report G or L for global/local, and this will always be a a
local variable.
NeilBrown [Tue, 9 Nov 2021 02:44:27 +0000 (13:44 +1100)]
oceani: Make 'List' separate from Print
Create a stand-alone ExpressionList which uses the List binode rather
than the Print binode.
The Print statement no longer uses a NULL entry on the end of the list
to denode a trailing comma. Rather ->left is used for a normal print
list and ->right is used for a print list that has a trailing comma.
NeilBrown [Sat, 6 Nov 2021 04:54:52 +0000 (15:54 +1100)]
oceani: free variables as soon as they go out of scope.
Each 'exec' now keeps track of the variables that go out-of-scope when
the exec completes.
CondScope variables need to be re-linked when they get merged.
We now poison a variable when it is freed to ensure it doesn't get used
again by mistake.
The final cleanup now only needs to handle global variables
NeilBrown [Mon, 8 Nov 2021 08:35:25 +0000 (19:35 +1100)]
oceani: update min_depth promptly.
As the loop in var_block_close() continues until min_depth is too low,
we need to set it promptly to stop the same variable being processed
again before it has been merged.
NeilBrown [Sat, 6 Nov 2021 23:59:23 +0000 (10:59 +1100)]
oceani: create separate scope for do part of while
Any variables created in the do part won't be created in the final
iteration, so we want them to be constrained to the do part, not seen as
part of the whole loop body.
This makes while/do match if/then better.
NeilBrown [Sat, 6 Nov 2021 02:04:54 +0000 (13:04 +1100)]
oceani: move var_block_close() calls to the code sections that close the block
Rather than calling var_block_close() from common non-terminals, move
the calls into the body of the parent non-terminal. This places them
after the 'struct exec' which represents the scope has been created.
This is needed to attach the variables to the point where their scope is
closed, so they can be freed.
This change helped me focus on some untested - and broken - code.
NeilBrown [Fri, 5 Nov 2021 23:55:01 +0000 (10:55 +1100)]
oceani: simplify loop in var_block_close()
The 'step' was not in the 'for' header, which makes it harder to follow
how the loop works.
Also add a comment to explain where is happening when ->name->var != v.
NeilBrown [Sat, 30 Oct 2021 04:49:08 +0000 (15:49 +1100)]
oceani-tests: add test for declaring a CondScope variable
If a variable was declared in all branches of a structures command, it
may or may not be declared as something else afterwards.
We need to test both options.
NeilBrown [Sun, 17 Oct 2021 10:03:01 +0000 (21:03 +1100)]
oceani: move variable values to a stack frame.
We have two frames - one for global values (currently always constant)
and one for local variables.
When we get functions, the local variable frame will be managed with a
stack of frames.
NeilBrown [Sun, 17 Oct 2021 02:35:58 +0000 (13:35 +1100)]
oceani: add parse_context arg to all interp functions, and a few others.
When I switch variables to use a stack frame, I'll need the
parse_context available more broadly (as it will hold the stack).
So add it to a selection of functions now.
NeilBrown [Sat, 16 Oct 2021 05:58:42 +0000 (16:58 +1100)]
oceani: differentiate static-sized arrays from others.
Some arrays will always have the same size - a static size.
Others might have a different size each time their scope is entered, if
the size is calculates from a variable.
The latter need to be reallocated whenever scope is entered, the former
do not.
This will matter when we create call frames to be able to handle
recursion.
NeilBrown [Sat, 16 Oct 2021 05:27:41 +0000 (16:27 +1100)]
oceani: don't allocate init value for non-initialized fields.
Struct fields that aren't explicitly initialised must be initialized to
a 'null' value. This can happen at interp-time. There is no need to
allocate a null value when parsing.
NeilBrown [Thu, 14 Oct 2021 02:43:02 +0000 (13:43 +1100)]
oceani: handle variable-sized arrays better.
An array with size set by a constant variable(!) might have a different
size each time the declaration is encountered. So we need to
re-evaluate the size each time.
We currently re-evaluate the size only if it is zero.
So for numerical-constant sized arrays, evaluate size during parsing.
For other arrays, re-evaulate each time using a new prepare_type method.
NeilBrown [Tue, 12 Oct 2021 10:28:47 +0000 (21:28 +1100)]
oceani: fix a couple of issues
1/ when a variable declared in a loop was re-initialized, we didn't free
the old value before allocating a new one.
2/ When assigning to an out-of-bounds array index, created an rval,
but never freed it.