Create an executable for a program in an interpreted language: Difference between revisions

Added Wren
(→‎{{header|AWK}}: Added sample input and output)
(Added Wren)
Line 341:
remove( "/tmp/t" );
}</lang>
 
=={{header|Wren}}==
Wren source code is always compiled first into an intermediate bytecode using a single-pass compiler which is part of its virtual machine (VM). The VM then interprets the bytecode at runtime with respect to the underlying platform which can be Linux, MacOS, Windows or (in theory at least) anything else for which a standard C99 compiler is available.
 
Note that, for various reasons, it is not currently possible to intercept the bytecode stream prior to interpretation which would enable a native code AOT compiler to be written for the language and, whilst a JIT compiler would be theoretically possible, Wren's inventor thought that this would severely compromise the essential simplicity of the VM.
 
Wren is designed for embedding and, technically, even ''Wren-cli'' - which enables Wren scripts to be run from the command line - is just a host application for the Wren VM which uses the cross-platform library, ''libuv'', to provide additional functionality (mainly I/O) not provided by Wren's standard library itself.
 
If we don't need this additional functionality, we can instead write a simple C host, link it to the Wren VM library and then use the latter to compile and run a Wren source code file. In fact, the VM is so small that its source could be embedded directly into the C host as could the Wren source itself but, in the interests of tidiness and versatility, we won't do that here.
 
So this is perhaps the nearest we can get to the spirit of this task. The following C program (''wrenc.c'') could be used:
 
<lang C>/* gcc -O3 wrenc.c -o wrenc -lwren -lm */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wren.h"
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
size_t ret = fread(script, 1, fsize, f);
if (!ret) perror("Error reading wren source file.");
fclose(f);
script[fsize] = 0;
return script;
}
 
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}
 
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}
 
int main(int argc, char **argv) {
if (argc != 2) {
printf("Please pass the name of the Wren file to be executed.\n");
return 1;
}
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.loadModuleFn = &loadModule;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = argv[1];
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
wrenFreeVM(vm);
free(script);
return 0;
}</lang>
 
If we now create a Wren source code file: ''countdown.wren'':
<lang ecmascript>for (i in 5..0) System.print(i)</lang>
 
we can compile and run it and obtain the expected output (on Linux) as follows:
{{out}}
<pre>
$./wrenc countdown.wren
5
4
3
2
1
0
</pre>
9,482

edits