Tags
There are no tags for this page.
Attachments
Perl 6
SMOP sm0p Language
sm0p
Basic Structure
sm0p has a simple structure of a finite set of nodes. Each node is represented by a statement, and no inner blocks are allowed. It is delimited by the q:sm0p { ... } construct, and must be used as the rvalue of a C assignement like: "continuation = q:sm0p { ... }".
Every symbol is replaced by its C counterpart, which means that they are resolved at "definition time". On the other hand, the defined operations will only be executed later by the interpreter at "runtime". As sm0p is really a macro language, there's no much sense in defining a "compile time"
Statement
Each statement is composed by three parts:
- Optional Label
- Invocant / Responder
- Identifier
- Capture
And this three parts are always resolved at definition time, with the following rules:
- If they have a $ sigil, they should be resolved as local C variables.
- Barewords are treated as constant identifiers, use q:identifier[infix:+] for non alphanumerics
- SMOP__SLIME__Capturize.new(x,(a,b,c),(q,w,e),z) is translated directly to its lowlevel equivalent and usually appears as the argument to the move_capturize call
- When there are mixed named and positional arguments, the named must be before (for parsing reasons)
- Labels are defined to with label: in front of the node and refered to as `label (the translate to number representing the relative position of the labeled node
The messages are composed by:
- taking the responder interface of the invocant as the responder for the message.
- translating the capture of the call to a native capture creation, using the invocant unless other invocant is defined.
- taking the identifier as is.
- When the capture have the prefix:<|> operator, the given object is set as the capture instead of composing a capture with the object
Example
The default implementation of the interpreter in SMOP now is pretty lame. The sm0p language is a macro language that will translate from a higher-level meaningfull language to a set of repetitive C calls that noone wants to write by hand. The exemple seems to be the better way to illustrate that.
// c code before here
continuation = q:sm0p {
$current;
$interpreter;
$obj.DESTROYALL(|$obj);
$SMOP__SLIME__CurrentFrame.move_capturize(
SMOP__SLIME__Capturize.new(2,(3),(),3));
$SMOP__SLIME__CurrentFrame.forget();
$SMOP__SLIME__CurrentFrame.free(|$obj);
$interpreter.goto()
};
// c code after here
This embedded code, that means:
continuation = Frame.new(
Node.new(
result => $current
),
Node.new(
result => $interpreter
),
Node.new(
responder => ___RI___($obj),
identifier => DESTROYALL,
capture => $obj,
),
Node.new(
responder => ___RI___(SMOP__STACK__CurrentFrame),
identifier => move_capturize,
capture => \( SMOP__STACK__OPCAPTURE_Move_Capturize.new(2,(3),(),3) ),
),
Node.new(
responder => ___RI___(SMOP__STACK__CurrentFrame),
identifier => forget,
),
Node.new(
responder => ___RI___(SMOP__STACK__CurrentFrame),
identifier => free,
capture => $obj,
),
Node.new(
responder => ___RI___($interpreter),
identifier => goto,
capture => \( $interpreter: )
)
);
Would be translated by a pre-processor to:
continuation = SMOP_DISPATCH
(NULL, SMOP__SLIME__Frame, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Frame,
(SMOP__Object*[]){
// $current;
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__result,
current
})),
// $interpreter;
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__result,
interpreter
})),
// $obj.DESTROYALL(|$obj);
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__responder,
SMOP_RI(obj),
SMOP__ID__identifier,
SMOP__ID__DESTROYALL,
SMOP__ID__capture,
obj
})),
// SMOP__SLIME__CurrentFrame.move_capturize(
// SMOP__SLIME__Capturize.new(2,(3),(),3));
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__responder,
SMOP_RI(SMOP__SLIME__CurrentFrame),
SMOP__ID__identifier,
SMOP__ID__move_capturize,
SMOP__ID__capture,
SMOP__NATIVE__capture_create(SMOP__SLIME__CurrentFrame, SMOP__SLIME__Capturize_create(2,(int[]){3,0}, NULL, 3));
})),
// SMOP__SLIME__CurrentFrame.forget();
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__responder,
SMOP_RI(SMOP__SLIME__CurrentFrame),
SMOP__ID__identifier,
SMOP__ID__forget
})),
// SMOP__SLIME__Operators.free(|$obj);
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__responder,
SMOP_RI(SMOP__SLIME__Operators),
SMOP__ID__identifier,
SMOP__ID__free,
SMOP__ID__capture,
SMOP__NATIVE__capture_create(obj, NULL, NULL)
})),
// ___INTERPRETER___.goto()
SMOP_DISPATCH
(NULL, SMOP__SLIME__Node, SMOP__ID__new,
SMOP__NATIVE__capture_create
(SMOP__SLIME__Node, NULL,
(SMOP__Object*[]){
SMOP__ID__responder,
SMOP_RI(___INTERPRETER___),
SMOP__ID__identifier,
SMOP__ID__goto
})),
}));
|