Something something computer languages, what their source code means, and what it means to interpret/compile/execute different types of programs, or perform other operations on them.
Some concepts that a program (in source or compiled format) can be thought to represent:
A given language influences how we think about a program in that language, but one may of course do whatever they want with the source code.
e.g. You could read a Perl program and run it. Or you could compile it to some other representation, then generate an object with methods to either run the Perl script or dump out its original source code. What do you call that operation?
The difference between 'a sequence of tasks' (bash script)
and 'a machine that executes a sequence of tasks' (C program)
is not inherent to the program itself -- you could compile
bash scripts or interpret C programs.
But the language does influence the way we think of it.
Bash scripts are executed top-to-bottom,
but C programs have a main function.
This gives the author of a C program more control over
what happens at compile-time (determining struct layouts, macro and constexpr evaluation)
vs execution-time (the sequence of operations in main)
whereas a bash programmer doesn't get to choose.
My goal is to give names to some common operations that can be done on source code, along with the expected behavior.
Note that some operations transform to another form with the same meaning
(CompileToExecutable, Simplify), but others
output something with a different meaning than the input
(JanetCompile, Evaluate),
and others are operations that are run for side-effects and don't
neccesarily have a single 'output' (Execute).
Whether you think of an operation as a procedure that takes an input and immediately does something, or as a constructor for an action is up to you. The distinction is this whole discussion again!
Execute and CompileToExecutable only make sense for languages that represent actions, because 'execute' is inherently about actions.
'Interpret' could mean many different things, so I will not use that word to name an operation. You can interpret a program many different ways, which may or may not include executing anything. For example, you might interpret an SVG file in order to find the minimum bounding box of all of the paths described by the SVG.
Interpret a script or compiled program and immediately do what it says. For command-line programs, this might mean reading/writing from stdin/stdout, other files, and/or environment variables, and eventually exiting with some exit code. Or anything else! Executing arbitrary programs is somewhat dangerous in this way, since they can do anything.
Execution always implies some context.
Find the result of a functional program, without applying any side-effects. Functional programs can represent actions to be done, but evaluating them won't cause those to happen.
The result of evaluation may be some abstract value. To actually do anything useful requires something to be done with the result of evaluation. For example:
i.e. the result of evaluation is the same kind of thing as the thing that was evaluated, and all these same operations may be applied to it.
TODO: Would evaluating the result of evaluation just return the same result again? i.e. is 'evaluate' the same as 'simplify'? Or does evaluating an expression return a different kind of thing, such that evaluating the result might not make sense, or, if the result of evaluating an expression A is another expression B, evaluating B may have a completely different meaning than evaluating A? Maybe I should differentiate between 'simplify' and 'evaluate'.
The identity operation, at least for things for which 'printing' is well-defined (i.e. probably text or byte sequences, depending on context).
Takes the source and print it directly to stdout!
This is the default for PHP scripts that don't include <?php.
A class of operations, really, because there are different types of modules. e.g. a DLL, a shared object, a static object file, a Java class file, a compiled Python module, etc.
Essentially this means that the output is an object that can be loaded by another program without necessarily 'executing' it.
Generally this implies no side-effects.
Read a representation of some object without executing anything.
Some platforms don't have a clean way to do this;
specifically those whose module systems are implemented
by executing the module's code, e.g. Ruby or PHP modules.
In those systems, there is no LoadObject operation,
just an Execute that runs in the same interpreter context
as the script that included the module.
Input: source code.
Output: something that can be executed, and have the same behavior that executing the script directly would have had.
Intended to be immediately executed line-by-line. Executing a line may be required in order to properly parse the next line! So there is no way to straightforwardly 'compile' a TScript34.2 script other than by wrapping the original source, though some optimizations may be possible if the compiler understands the operations well enough to know that it can rely on them to not change the state of the parser or not have other side-effects.
Notable in that compiling a Janet program
involves executing it as a script and then saving the state as an executable
that, when run, invokes the main function.
So let's give names to the different operations:
main without running itmainEffectively, janet script.janet does a JanetExecute,
which is the same as the Execute I defined earlier.
janet -c script.janet script.jimage, on the other hand,
is kind of special. It doesn't fit Execute (not to mention that
I just declared Execute to mean what janet script.janet does),
and it doesn't fit my definition of CompileToExecutable, either,
because it potentially has side-effects, and
because the compiled program won't include side-effects that executing the source directly would have done.
I don't know of any other system that works quite like this,
so let's give 'what janet -c does' its own term
with its own semantics, JanetCompile.