Skip to content

Annotation Proposal

Callum edited this page Apr 6, 2022 · 4 revisions

Annotations

Annotations are values stored in chunks and function definitions accessed through the Closure class. These allow for Metadata to be included in scripts. This is enabled only for C-Like mode.

Writing Annotations

Annotations for functions will be specified in code with @name value, the name immediately following the @ symbol, and the value being a valid expression that can be evaluated at compile time. These include string literals, numbers, booleans, and tables with values consisting of those types.

To specify annotations for a chunk, use @@ instead of @ to attach it to the compile unit.

@@meta 1.0

@functionmeta "string"
@meta2 { hello: 'world' }
function hello()
{

}

This will add the annotation meta with value 1.0 to the chunk, and the annotation functionmeta with value "string" to the hello() function. meta2 on the function will contain a table with the data hello = world

Directives

Chunk-level annotations may also be specified as compiler directives. ScriptOptions will contain a directives property with a list of keywords. If a directive keyword is matched by the compiler, the following text will become the value of an annotation until either a semicolon or any whitespace is reached. This is stored as a string literal.

//Script Options
List<string> Directives { get; set; }

//Example
script.Options.Directives.Add("using");

DynValue v = script.LoadString("using A.B.C;");

Console.WriteLine(v.Closure.Annotations[0].Name); //"using"
Console.WriteLine(v.Closure.Annotations[0].Value); //"A.B.C"

Enabling Annotations

ScriptOptions will contain an instance of IAnnotationPolicy, an interface defined by:

public enum AnnotationResult
{
    Allow,
    Ignore,
    Error
}
public interface IAnnotationPolicy
{
    AnnotationResult OnChunkAnnotation(string name, string value);
    AnnotationResult OnFunctionAnnotation(string name, string value);
}

OnChunkAnnotation and OnFunctionAnnotation control the compiler's behaviour when encountering an annotation. A result of Allow will store the annotation in the bytecode, Ignore will not store the annotation, and Error will throw a compiler error.

Three default policies will be implemented, AnnotationPolicies.Allow, AnnotationPolicies.Ignore, AnnotationPolicies.Error. These will store all annotations, ignore all annotations, or error on any annotation respectively. The default value will be set to Allow.

Loading from bytecode will bypass the annotation policy as it only controls the compiler.

Accessing Annotations

Add to Closure class. Default initialised to Array.Empty<ClosureAnnotation>() Use the LoadFile/LoadString/LoadStream functions of script to get a DynValue containing the closure for the main script chunk.

public ClosureAnnotation[] Annotations { get; private set; }
public class ClosureAnnotation
{
    public string Name { get; private set; }
    public DynValue Value { get; private set; }
    
    public ClosureAnnotation(string name, DynValue value)
    {
        Name = name;
        Value = value
    }
}

In the bytecode these annotations will be stored in a special Annot instruction included immediately after Meta. If there are no annotations, no Annot opcode will be emitted.