Age | Commit message (Collapse) | Author |
|
lib: remove fixed capture group limit in match() and regex replace()
|
|
Instead of supporting only up to 10 potential regular expression captures,
infer the amount of required captures directly from the compiled regexp
structure and allocate the match range array dynamically.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Extend the `render()` function to accept a function value as first argument,
which allows running arbitrary ucode functions and capturing their output.
This is especially useful in conjunction with `loadfile()` or `loadstring()`
to dynamically compile templates and rendering their output into a string.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- getenv(): Allow querying the entire environment by omiting variable name
- split(): Properly handle null bytes in subject and separator strings
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Since commit 3c168b5 ("vm, cli: move search path into global config...")
it is required to explicitly initialize the module search path in the
configuration structure for compile time module imports and run time
require operations to work.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When building with gcc-10 and -O2, the following warning in ubus.c is
triggered during the compilation:
In function ‘uc_ubus_object_register’,
inlined from ‘uc_ubus_publish’ at .../ubus.c:1521:10:
.../ubus.c:1464:14: error: ‘strncpy’ output truncated before terminating nul copying as many bytes from a string as its length [-Werror=stringop-truncation]
1464 | obj->name = strncpy(onptr, ubus_object_name, namelen);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../ubus.c: In function ‘uc_ubus_publish’:
.../ubus.c:1447:12: note: length computed here
1447 | namelen = strlen(ubus_object_name);
| ^~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Solve this issue by using memcpy() instead. We already take care of
allocating a zeroed, strlen() + 1 sized destination buffer so loosing
the `\0` byte of the source string is perfectly fine.
Fixes: #100
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
lib: introduce three new functions call(), loadstring() and loadfile()
|
|
Introduce new functions dealing with on-the-fly compilation of code and
execution of functions with different global scope.
The `loadstring()` and `loadfile()` functions will compile the given
ucode source string or ucode file path respectively and return the entry
function of the resulting program.
An optional dictionary specifying parse options may be given as second
argument.
Both functions return `null` on invalid arguments and throw an exception
in case of compilation errors.
The `call()` function allows invoking a given function value with a
different `this` context and/or a different global environment.
Finally refactor the existing `uc_require_ucode()` implementation to
reuse the new `uc_loadfile()` and `uc_call()` implementations and adjust
as well as simplify affected testcases.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Factor out the nested syntax error message indentation logic into a
separate helper procedure for reuse in other places.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Align the path resolving logic with compiler.c and use strrchr() and a
width limited printf pattern to extract the directory name portion.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When loading a precompiled program from stdin, the input source runpath
is unset which subsequently leads to a null pointer being passed to
uc_source_runpath_set() when will then attempt to strdup() it, leading
to a null pointer access.
Properly handle this case and only duplicate non-null pointers.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When a module function with unpatched upvalues is freed, ucv_free() might
access a NULL pointer through ucv_put_value(), so make sure to skip those
unset upvalue slots when freeing a closure.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Implement periodic GC
|
|
Implement a new flag `-g` which takes an interval value and enables the
periodic GC with the given interval for cyclic object structures in the
VM if specified.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce a new stdlib function `gc()` which allows controlling the periodic
garbage collector from ucode.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce two new VM api functions uc_vm_gc_start() and uc_vm_gc_stop()
which allow starting and stopping automatic periodic garbage collection
of cyclic objects in the VM context.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
We must not free objects being in the module export registry.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Add import statement support for dynamic extensions
|
|
Utilize the new I_DYNLINK vm opcode to support import statements referring
to dynamic extension modules.
During compilation, the compiler will try to infer the type of the imported
module from the resolved file path; if it ends with `.so`, the module is
assumed to by a dynamic extension and loading/binding of the module is
deferred to runtime using I_DYNLINK opcodes.
Additionally, the `-c` cli option gained support for a new compiler flag
`dynlink=...` which allows forcing a particular module name expression
to be treated as dynamic extension. This is useful to e.g. force resolving
`import { x } from "foo"` to a dynamic extension `foo.so` loaded at runtime
even if a plain `foo.uc` exists in the search path during compilation or if
no such module is available at build time.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The I_DYNLOAD opcode is basically a bytecode level instruction for
uc_require() with semantics similar to I_IMPORT. It allows loading
a dynamic extension library at runtime and treating values from the
resulting module context object like exports from a compile time source
module.
For example the statement `import { readfile, writefile } from "fs"`
would import the readfile() and writefile() functions of fs.so as
readonly live bindings into the current file scope.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Break out the core logic of the uc_require() stl function into a new
uc_require_library() helper function and make it available for usage
outside of lib.c. Also add a new boolean parameter to the helper function
which allows restricting runtime require operations of modules to dynamic
libraries only.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Try to resolve the source offset to line and character position and only
fall back to report the location as instruction offset if we weren't able
to determine the line number.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
If a compile error is raised at offset 0, try to resolve line and
character position anyway.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
|
|
Indent inner messages and prepend them with a vertical bar to increase
visual separation of messages. Also include file name in source context
output when the compiled program contains more than one source file.
Adjust affected testcase outputs accordingly.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Since we track the offsets in the compiler directly now there's no need
to keep this function.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The current implementation of the module export offset tracking was
inadequate and failed to properly handle larger module dependency
graphs. In order to properly support nested module imports/exports,
the following changes have been introduced:
- Gather export slots during module compilation and emit corresponding
export opcodes as one contiguous block at the end of the module
function body, right before the final return. This ensures that
interleaved imports of other modules do not place foreign exports
between our module exports.
- Track the number of program wide allocated export slots in order
to derive per-module-source offsets for the global VM export list.
- Derive import opcode source index from the module source export
offset and the index of the requested name within the module source
export name list.
- Improve error reporting for circular module imports.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The current implementation of `uc_compiler_canonicalize_path()` used the
entire runtime path of the source object as path prefix, not just the
directory part of it.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Disallow toplevel `return` statements in module functions
- Disallow `export` statements in non-module functions
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Module function upvalues are patched through import operations, ensure to
leave them uninitialized when loading and executing the module constructor.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce a further uc_function_t structure member indicating whether the
underlying function is a module constructor.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Module import export support
|
|
Trim down the libucode.so size somewhat by marking purely internal,
non-public API functions hidden.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
This commit introduces syntax level support for ES6 style module import
and export statements. Imports are resolved at compile time and the
corresponding module code is compiled into the main program.
Also add testcases to cover import and export statement semantics.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Do not require a parent function compiler reference to lookup an already
declared (potentially unresolved) upvalue in the current scope. Instead,
search the named upvalues in the current function scope in case there is
no parent compiler reference.
This is required for the upcoming module support which will use unresolved
upvalues to realize import/export functionality.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
So far we allowed anonymous toplevel function expressions which makes
little sense since those can't be used for anything.
Require toplevel function declarations to be named and turn a missing
name into a compile time syntax error.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Report the proper source location when raising an error due to an
increment/decrement operation on a constant value.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Replace all occurrences for the test file directory path with "." in stderr
and stdout results to ensure stable test outputs.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The upcoming compile-time module support will require the configured
extension search path in the compiler as well, so move it to the
already shared uc_parse_config_t structure and add the appropriate
utility functions to initialize, append and free the search path
vector.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce new opcodes to realize module imports and exports. The export
operation will capture a local variable as upvalue and store it in VM
wide module export registry while the import operation will connect an
upvalue from the module export registry with a preallocated upvalue in
the running function scope.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Reject modifications on object and array values with a type exception when
the constant flag is set on the value operated upon.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Resolve upvalue references to their actual values when pushing such
references onto the stack (or when attempting to call them as method).
This allows constructing objects of pointers, as needed for wildcard
module imports.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Upcoming module support will rely on upresolved upvalues which are patched
at runtime to realize module imports, make sure the VM trace code does not
choke on such unresolved upvalues.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Add a helper function to query the global index of a named export within
a specific source which is a prerequisite for compiling import statements.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The upcoming module support requires maintaining multiple source objects
within the same program, so add the necessary infrastructure for it.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
We must always report the chunk source position relative to the function
start offset, even if it is zero.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The sizeof(size_t) might differ from the sizeof(uint32_t) used to serialize
compiled bytecode, so extra care is needed to properly encode and decode
upvalue slot values which are defined as (size_t)-1 / 2 + n.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Extend abstract source objects to maintain a list of exported symbols and
add functions to append and lookup exported names.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|