Commit graph

89 commits

Author SHA1 Message Date
9ce5c20736 No longer evaluate exprs directly 2022-04-21 21:17:17 +02:00
b7c88635d9 Redo source reader interface
The callback and the opaque data are now grouped together in a struct
instead of being passed individually into the tokenizer.

This also exposes the string source reader struct and therefore removes
the need of heap allocating it. Neat!
2022-04-15 22:35:36 +02:00
70c3d6e3e4 README: Fix spelling mistakes 2022-04-15 17:13:30 +02:00
82a9858902 apfl_value_hash: Return directly instead of "goto ok" 2022-04-15 14:49:28 +02:00
b3322c93e9 Move scope functions/structs out of context.[ch] 2022-04-15 14:41:22 +02:00
6add5e47b9 hashmap: Improve cursor / peek API
- peek functions will now return pointers directly
- cursor access methods can now return an error, if the cursor is already
  at the end

Also rewrote some cursor loops to use the HASHMAP_EACH macro.
2022-04-11 23:31:20 +02:00
f26759b3f0 expr: Remove refcount in body elements 2022-04-11 22:44:04 +02:00
90a80152e1 Implement mark&sweep garbage collection and bytecode compilation
Instead of the previous refcount base garbage collection, we're now using
a basic tri-color mark&sweep collector. This is done to support cyclical
value relationships in the future (functions can form cycles, all values
implemented up to this point can not).

The collector maintains a set of roots and a set of objects (grouped into
blocks). The GC enabled objects are no longer allocated manually, but will
be allocated by the GC. The GC also wraps an allocator, this way the GC
knows, if we ran out of memory and will try to get out of this situation by
performing a full collection cycle.

The tri-color abstraction was chosen for two reasons:

- We don't have to maintain a list of objects that need to be marked, we
  can simply grab the next grey one.
- It should allow us to later implement incremental collection (right now
  we only do a stop-the-world collection).

This also switches to a bytecode based evaluation of the code: We no longer
directly evaluate the AST, but first compile it into a series of
instructions, that are evaluated in a separate step. This was done in
preparation for inplementing functions: We only need to turn a function
body into instructions instead of evaluating the node again with each call
of the function. Also, since an instruction list is implemented as a GC
object, this then removes manual memory management of the function body and
it's child nodes. Since the GC and the bytecode go hand in hand, this was
done in one (giant) commit.

As a downside, we've now lost the ability do do list matching on
assignments. I've already started to work on implementing this in the new
architecture, but left it out of this commit, as it's already quite a large
commit :)
2022-04-11 22:24:22 +02:00
4088fdd1c3 Fix typo 2022-02-25 21:54:27 +01:00
bb464d8226 Hashmap: Implement prepared setting
With a prepared set, the potential allocation, which can fail, is split
from the actual setting, which can not fail.
2022-02-25 20:50:43 +01:00
40320aaa4a Fix copying dicts
We didn't properly copy the opaque value before (a heap-allocated allocator
pointer), resulting in a use-after-free of the opaque on the copied map if
the old map was destroyed.
2022-02-15 22:32:15 +01:00
8df0991415 eval.c: Don't create copy of already refcounted string 2022-02-14 21:56:36 +01:00
5f8462fe34 Add apfl_stackidx typedef
This makes it clear that a value of that type is meant as an index into the
stack.
2022-02-10 22:39:39 +01:00
09c6459565 Fix typo 2022-02-10 22:04:48 +01:00
d86c9375a4 Shorter name for internal enum apfl_value_type 2022-02-10 21:56:48 +01:00
dd314c5abb Shorter name for internal enum get_item_result 2022-02-10 21:56:30 +01:00
78bd057c37 eval.c: Free the stack with FREE_LIST instead of FREE_OBJ
This way we pass the correct oldsize to the allocator.
2022-02-09 20:44:21 +01:00
ebf3fc89ff Introduce allocator abstraction
We now no longer call malloc/free/... directly, but use an allocator object
that is passed around.

This was mainly done as a preparation for a garbage collector: The
collector will need to know, how much memory we're using, introducing the
collector abstraction will allow the GC to hook into the memory allocation
and observe the memory usage.

This has other potential applications:

- We could now be embedded into applications that can't use the libc
  allocator.
- There could be an allocator that limits the total amount of used memory,
  e.g. for sandboxing purposes.
- In our tests we could use this to simulate out of memory conditions
  (implement an allocator that fails at the n-th allocation, increase n by
  one and restart the test until there are no more faked OOM conditions).

The function signature of the allocator is basically exactly the same as
the one Lua uses.
2022-02-08 22:53:13 +01:00
ad80ff8f85 Remove dead code 2022-02-08 21:42:54 +01:00
db0fb2aee4 expr: Make body objects refcounted
We'll soon need this, once we implement function definitions
2022-01-22 17:16:28 +01:00
0ab36ec37e hashmap: Add test cases
Also get rid of the silly hashmap_foo demo program.
2022-01-22 15:57:10 +01:00
d539b920c9 test.h: Don't force tests to use must_alloc 2022-01-22 15:56:19 +01:00
2966d6dc7c hashmap: Don't hide hashmap struct behind a pointer any more
Since the hashmap is meant for internal use only, there is no need to hide
the internal data. This also allows us to save some malloc() calls.
2022-01-22 15:55:56 +01:00
afd5d8e1d2 Makefile.am: Add missing internal header 2022-01-22 15:48:17 +01:00
21efc85dba Convert to Lua-style stack API
Only for evaluating expressions for now and right now the only exposed
operation is to debug print a value on the stack, this obviously needs to
be expanded.

I've done this for two reasons:

1. A Lua-style stack API is much nicer to work with than to manually manage
   refcounts.
2. We'll soon need a more sophisticated garbage collector (if you even want
   to count the refcounting as garbage collection). For this, the GC will
   need root objects to start tracing for live objects, the stack will be
   one of these roots.
2022-01-20 22:45:09 +01:00
cc79bab69f resizable: Implement splicing 2022-01-20 21:33:04 +01:00
d81bef9184 parser/tokenizer: Save textual data as refcounted strings
This avoids creating refcounted strings during evaluation and makes it
easier to use the same parsed string in multiple places (should be
useful once we implement functions).
2022-01-18 21:18:27 +01:00
c9a935b161 Support assigning into dictionaries
You can now set keys in dictionaries to a value. If a key in a key path is
missing, we automatically create an empty dictionary. Otherwise setting
deeply nested keys becomes annoying.
2022-01-15 23:09:24 +01:00
2684f1e61e Fix copying hashmaps
- len == 0 wasn't handled propery
- Incorrect source k/v address
- New object was never returned m(
2022-01-15 23:01:23 +01:00
ce37113f93 Fix some missing allocation checks / length checks 2022-01-15 21:51:40 +01:00
2162b8b580 Add a README
This roughly describes the syntax and semantics of the language
2022-01-14 23:25:57 +01:00
a14b490dfe Partially implement pattern matching assignments
We're still missing predicates (need to be able to call functions for that
one) and assignments into dictionaries. But we now can deconstruct a list
and check against constants.

So things like this work now:

	[1 foo ~bar [a b]] = [1 "Hello" 2 3 4 [5 6]]
	# foo is: "Hello"
	# bar is: [2 3 4]
	# a is: 5
	# b is: 6

Pretty cool :)
2022-01-14 23:25:57 +01:00
ae45aeebe2 parser+expr: Handle blank identifier (_) 2022-01-08 23:20:29 +01:00
50cd2c18d2 expr+parser: Restrict what an assignable can be
If you assign into a member access (`foo.bar = baz` or `foo@bar = baz`), it
is no longer permitted that the LHS of the at/dot is an arbitrary
assignable. It now must be a variable, at or dot. This disallows some silly
constructs (e.g. `[foo]@bar = baz`), increases the similarity to function
parameters and should make writing the evaluation code for these more easy.
2022-01-08 23:06:22 +01:00
ac3af0baf1 apfl_ctx_destroy: Do nothing on NULL input 2022-01-08 22:09:43 +01:00
6439f4f8ce Tokenizer: Disallow ASCII control characters outside strings 2022-01-07 23:39:06 +01:00
4eea93ff97 Improve AST representation of expansion in assignables / parameters
The previous representation didn't properly model the fact that an
assignable / parameter can only be expanded, if it's a list element. This
now better models this. Other than being more correct, this should also
make evaluating these a bit easier.

While I was at it, I also improved the error message for multiple
expansions on the same level and added tests for these.
2022-01-07 23:08:25 +01:00
e928f40da4 Implement simple variable support
We can now assign to variables and retrieve their values. Not all
assignables are implemented yet, but still pretty cool :).
2022-01-06 22:53:26 +01:00
bab1812cc9 Add tokenizer tests to check binary string handling 2022-01-06 22:50:44 +01:00
76f3c776a0 Add parser tests for function calls 2022-01-06 22:50:14 +01:00
96b1fecdcd Hashmap: Make copy callbacks return void
Since we're using refcounts, we don't really copy anything and no error can
occur. So let's make these callbacks return void to simplify things. This
also makes the return value false of the value getters unambiguous: It now
always means that the key was not present.
2022-01-05 21:54:37 +01:00
7903686fe7 Parser: Fix not setting error when -> is missing in dictionaries 2022-01-05 21:50:50 +01:00
721d2d2d21 Implement evaluating container member access 2022-01-05 00:25:41 +01:00
0384875ef3 values: Split lists into read-only lists and editable lists
This is analogous to dictionaries and ensures that no circular references
can be created when using the exported API in apfl.h.

This also changes apfl_value_copy into apfl_value_incref to better reflect
what it does and to reflect that it is no longer an operation that can
fail.
2022-01-04 23:11:38 +01:00
c98a4f4fe9 Remove apfl_function_response
Accidentally comitted that already
2022-01-04 21:56:52 +01:00
f3d0bbed17 Implement evaluating dictionary literals
We can now have dictionaries with keys and values of arbitrary types.
Very cool! :)
2022-01-04 21:51:44 +01:00
8b5d881ab9 Fix typos 2022-01-04 21:29:13 +01:00
00e19ce242 Hashmap demo: Fix hashing string
Not sure this ever worked...
2022-01-04 21:28:38 +01:00
eaa6b723bc Fix refcounted strings
Increasing the refcount (confusingly called copy before, fixed that too)
didn't work properly, as the object was copied and the refcount was only
updated in one of the copies.
2022-01-04 21:22:46 +01:00
27eaefaaaa value.c: Print empty list into single line 2022-01-02 21:23:41 +01:00