Internal Compiler API - Lambda-Mountain-Compiler-Backend/lambda-mountain GitHub Wiki
If you want to write a plugin for LM, then it may be necessary to interface with compiler objects. These APIs presented here are stable and will be supported by their nominal type signature.
If something is not present here in the type signature, then it may not be stable. For example, destructuring types used in these functions may be unstable.
Types here should be treated as opaque, even if they are not defined as explicitly opaque.
type AST;
type Type;
type TContext;
# var-to-def-index permits lookup from variable reference to variable definition
#
# a variable reference will resolve to either
# a local variable: finding the original local binding definition
# a global variable: finding the original global binding definition
#
let var-to-def-index = {} :: Hashtable<AST,AST>;
Simple function application can be fairly complicated when considering all of the various inference rules present in the type system. The "apply" set of functions take function types and argument types to produce return types, providing a unified interface for inference.
let apply(functions-type: Type, arguments-type: Type): Type;
Ground types have short-hand constructors.
# Ground Types
let t1(tag: CString, p1: Type): Type;
let t2(tag: CString, p1: Type, p2: Type): Type;
let t3(tag: CString, p1: Type, p2: Type, p3: Type): Type;
# Type Variables
let tv(tag: CString): Type;
# Top Type
let ta: Type;
# Conjunction
let $"&&"(lt: Type, rt: Type): Type;
Ground types have short-hand destructors.
# Get type parameter, starting from left (l1) moving left (l2), (l3), ...
let .l1(tt: Type): Type; # T<a,b,c,d> .l1 = a
let .l2(tt: Type): Type; # T<a,b,c,d> .l2 = b
let .l3(tt: Type): Type; # T<a,b,c,d> .l3 = c
let .l4(tt: Type): Type; # T<a,b,c,d> .l4 = d
let .l(tt: Type, i: USize): Type; # ...
# Get type parameter, starting from right (r1) moving left (r2), (r3), ...
let .r1(tt: Type): Type; # T<a,b,c,d> .r1 = d
let .r2(tt: Type): Type; # T<a,b,c,d> .r2 = c
let .r3(tt: Type): Type; # T<a,b,c,d> .r3 = b
let .r4(tt: Type): Type; # T<a,b,c,d> .r4 = a
let .r(tt: Type, i: USize): Type; # ...
Types have a normal form with minimal inferable information, and a denormal form with maximal inferable information. Super-normal form refers to the type of a left-hand-side binding such as a variable, which may discard some information.
let normalize(tt: Type): Type;
let denormalize(tt: Type): Type;
let supernormalize(tt: Type): Type;
Unification is a process by which type information is compared or merged.
can-unify
is much faster than unify
.
let can-unify(supertype: Type, subtype: Type): Bool;
let unify(supertype: Type, subtype: Type): Maybe<TContext>;
The AST is starting to stabilize.
let mk-lit(val: CString): AST;
let mk-lit(val: SmartString): AST;
let mk-var(val: CString): AST;
let mk-var(val: SmartString): AST;
let mk-atype(tt: Type): AST;
let .ascript(t: AST, tt: Type): AST;
These methods are provided for common convenience.
let .into(t: AST, tgt: Type<String>): String;
let .into(tt: Type, tgt: Type<String>): String;