Files
kiss-vscode/src/hiss/Hiss.hx
2020-11-12 15:49:53 -07:00

119 lines
3.0 KiB
Haxe

package hiss;
import haxe.macro.Context;
import haxe.macro.Expr;
import hiss.Stream;
import hiss.Reader;
class Hiss {
/**
Build a Haxe class from a corresponding .hiss file
**/
macro static public function build(hissFile:String):Array<Field> {
var classFields = Context.getBuildFields();
var stream = new Stream(hissFile);
var reader = new Reader();
while (true) {
stream.dropWhitespace();
if (stream.isEmpty())
break;
var position = stream.position();
var nextExp = reader.read(stream);
trace(nextExp);
// The last expression might be a comment, in which case None will be returned
switch (nextExp) {
case Some(nextExp):
classFields.push(readerExpToField(nextExp, position));
case None:
stream.dropWhitespace(); // If there was a comment, drop whitespace that comes after
}
}
return classFields;
}
static function readerExpToField(exp:ReaderExp, position:String):Field {
return switch (exp) {
case Call(Symbol("defvar"), args) if (args.length == 2):
{
name: switch (args[0]) {
case Symbol(name):
name;
default:
throw 'The first argument to defvar at $position should be a variable name';
},
access: [APublic, AStatic],
kind: FVar(null, // TODO allow type anotations
readerExpToHaxeExpr(args[1])),
pos: Context.currentPos()
};
case Call(Symbol("defun"), args) if (args.length > 2):
{
name: switch (args[0]) {
case Symbol(name):
name;
default:
throw 'The first argument to defun at $position should be a function name';
},
access: [APublic, AStatic],
kind: FFun({
args: switch (args[1]) {
case List(funcArgs):
[
for (funcArg in funcArgs)
{
name: switch (funcArg) {
case Symbol(name):
name;
default:
throw '$funcArg should be a symbol for a function argument';
},
type: null
}
];
default:
throw '$args[1] should be an argument list';
},
ret: null,
expr: {
pos: Context.currentPos(),
expr: EReturn(readerExpToHaxeExpr(Call(Symbol("begin"), args.slice(2))))
}
}),
pos: Context.currentPos()
};
default:
throw '$exp at $position is not a valid defvar or defun expression';
};
}
static function readerExpToHaxeExpr(exp:ReaderExp):Expr {
var expr = switch (exp) {
case Symbol(name):
Context.parse(name, Context.currentPos());
case Str(s):
{
pos: Context.currentPos(),
expr: EConst(CString(s))
};
case Call(Symbol("begin"), body):
{
pos: Context.currentPos(),
expr: EBlock([for (bodyExp in body) readerExpToHaxeExpr(bodyExp)])
};
case Call(func, body):
{
pos: Context.currentPos(),
expr: ECall(readerExpToHaxeExpr(func), [for (bodyExp in body) readerExpToHaxeExpr(bodyExp)])
};
case RawHaxe(code):
Context.parse(code, Context.currentPos());
default:
throw 'cannot convert $exp yet';
};
trace(expr.expr);
return expr;
}
}