Fix tab/space format

This commit is contained in:
2020-11-14 17:26:54 -07:00
parent 3e074776d6
commit fadd9d32e2
11 changed files with 454 additions and 449 deletions

5
hxformat.json Normal file
View File

@@ -0,0 +1,5 @@
{
"indentation": {
"character": " "
}
}

View File

@@ -11,89 +11,89 @@ using StringTools;
typedef FieldFormFunction = (position:String, args:Array<ReaderExp>, convert:ExprConversion) -> Field;
class FieldForms {
public static function builtins() {
var map:Map<String, FieldFormFunction> = [];
public static function builtins() {
var map:Map<String, FieldFormFunction> = [];
map["defvar"] = varOrProperty.bind("defvar");
map["defprop"] = varOrProperty.bind("defprop");
map["defvar"] = varOrProperty.bind("defvar");
map["defprop"] = varOrProperty.bind("defprop");
map["defun"] = funcOrMethod.bind("defun");
map["defmethod"] = funcOrMethod.bind("defmethod");
map["defun"] = funcOrMethod.bind("defun");
map["defmethod"] = funcOrMethod.bind("defmethod");
return map;
}
return map;
}
static function fieldAccess(formName:String, fieldName:String) {
var access = [];
if (formName == "defvar" || formName == "defun") {
access.push(AStatic);
}
access.push(if (fieldName.startsWith("_")) APrivate else APublic);
return access;
}
static function fieldAccess(formName:String, fieldName:String) {
var access = [];
if (formName == "defvar" || formName == "defun") {
access.push(AStatic);
}
access.push(if (fieldName.startsWith("_")) APrivate else APublic);
return access;
}
static function fieldName(formName:String, position:String, nameExp:ReaderExp) {
return switch (nameExp) {
case Symbol(name):
name;
default:
throw 'The first argument to $formName at $position should be a variable name';
};
}
static function fieldName(formName:String, position:String, nameExp:ReaderExp) {
return switch (nameExp) {
case Symbol(name):
name;
default:
throw 'The first argument to $formName at $position should be a variable name';
};
}
static function varOrProperty(formName:String, position:String, args:Array<ReaderExp>, convert:ExprConversion):Field {
if (args.length != 2) {
throw '$formName with $args at $position is not a valid field definition';
}
static function varOrProperty(formName:String, position:String, args:Array<ReaderExp>, convert:ExprConversion):Field {
if (args.length != 2) {
throw '$formName with $args at $position is not a valid field definition';
}
var name = fieldName(formName, position, args[0]);
var access = fieldAccess(formName, name);
var name = fieldName(formName, position, args[0]);
var access = fieldAccess(formName, name);
return {
name: name,
access: access,
kind: FVar(null, // TODO allow type anotations
convert(args[1])),
pos: Context.currentPos()
};
}
return {
name: name,
access: access,
kind: FVar(null, // TODO allow type anotations
convert(args[1])),
pos: Context.currentPos()
};
}
static function funcOrMethod(formName:String, position:String, args:Array<ReaderExp>, convert:ExprConversion):Field {
if (args.length <= 2) {
throw '$formName with $args is not a valid function/method definition';
}
static function funcOrMethod(formName:String, position:String, args:Array<ReaderExp>, convert:ExprConversion):Field {
if (args.length <= 2) {
throw '$formName with $args is not a valid function/method definition';
}
var name = fieldName(formName, position, args[0]);
var access = fieldAccess(formName, name);
var name = fieldName(formName, position, args[0]);
var access = fieldAccess(formName, name);
return {
name: name,
access: access,
kind: FFun({
args: switch (args[1]) {
case ListExp(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(convert(CallExp(Symbol("begin"), args.slice(2))))
}
}),
pos: Context.currentPos()
};
}
return {
name: name,
access: access,
kind: FFun({
args: switch (args[1]) {
case ListExp(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(convert(CallExp(Symbol("begin"), args.slice(2))))
}
}),
pos: Context.currentPos()
};
}
}

View File

@@ -9,91 +9,91 @@ import kiss.SpecialForms;
import kiss.Macros;
class Kiss {
/**
Build a Haxe class from a corresponding .kiss file
**/
macro static public function build(kissFile:String):Array<Field> {
var classFields = Context.getBuildFields();
/**
Build a Haxe class from a corresponding .kiss file
**/
macro static public function build(kissFile:String):Array<Field> {
var classFields = Context.getBuildFields();
var stream = new Stream(kissFile);
var stream = new Stream(kissFile);
var readTable = Reader.builtins();
var fieldForms = FieldForms.builtins();
var specialForms = SpecialForms.builtins();
var macros = Macros.builtins();
var readTable = Reader.builtins();
var fieldForms = FieldForms.builtins();
var specialForms = SpecialForms.builtins();
var macros = Macros.builtins();
while (true) {
stream.dropWhitespace();
if (stream.isEmpty())
break;
var position = stream.position();
var nextExp = Reader.read(stream, readTable);
#if test
trace(nextExp);
#end
// The last expression might be a comment, in which case None will be returned
switch (nextExp) {
case Some(nextExp):
classFields.push(readerExpToField(nextExp, position, fieldForms, macros, specialForms));
case None:
stream.dropWhitespace(); // If there was a comment, drop whitespace that comes after
}
}
while (true) {
stream.dropWhitespace();
if (stream.isEmpty())
break;
var position = stream.position();
var nextExp = Reader.read(stream, readTable);
#if test
trace(nextExp);
#end
// The last expression might be a comment, in which case None will be returned
switch (nextExp) {
case Some(nextExp):
classFields.push(readerExpToField(nextExp, position, fieldForms, macros, specialForms));
case None:
stream.dropWhitespace(); // If there was a comment, drop whitespace that comes after
}
}
return classFields;
}
return classFields;
}
static function readerExpToField(exp:ReaderExp, position:String, fieldForms:Map<String, FieldFormFunction>, macros:Map<String, MacroFunction>,
specialForms:Map<String, SpecialFormFunction>):Field {
return switch (exp) {
case CallExp(Symbol(formName), args) if (fieldForms.exists(formName)):
fieldForms[formName](position, args, readerExpToHaxeExpr.bind(_, macros, specialForms));
default:
throw '$exp at $position is not a valid field form';
};
}
static function readerExpToField(exp:ReaderExp, position:String, fieldForms:Map<String, FieldFormFunction>, macros:Map<String, MacroFunction>,
specialForms:Map<String, SpecialFormFunction>):Field {
return switch (exp) {
case CallExp(Symbol(formName), args) if (fieldForms.exists(formName)):
fieldForms[formName](position, args, readerExpToHaxeExpr.bind(_, macros, specialForms));
default:
throw '$exp at $position is not a valid field form';
};
}
static function readerExpToHaxeExpr(exp:ReaderExp, macros:Map<String, MacroFunction>, specialForms:Map<String, SpecialFormFunction>):Expr {
// Bind the table arguments of this function for easy recursive calling/passing
var convert = readerExpToHaxeExpr.bind(_, macros, specialForms);
var expr = switch (exp) {
case Symbol(name):
Context.parse(name, Context.currentPos());
case StrExp(s):
{
pos: Context.currentPos(),
expr: EConst(CString(s))
};
case CallExp(Symbol(mac), args) if (macros.exists(mac)):
convert(macros[mac](args));
case CallExp(Symbol(specialForm), args) if (specialForms.exists(specialForm)):
specialForms[specialForm](args, convert);
case CallExp(func, body):
{
pos: Context.currentPos(),
expr: ECall(readerExpToHaxeExpr(func, macros, specialForms), [for (bodyExp in body) readerExpToHaxeExpr(bodyExp, macros, specialForms)])
};
case ListExp(elements):
{
pos: Context.currentPos(),
expr: ENew({
pack: ["kiss"],
name: "List"
}, [
{
pos: Context.currentPos(),
expr: EArrayDecl([for (elementExp in elements) convert(elementExp)])
}
])
}
case RawHaxe(code):
Context.parse(code, Context.currentPos());
default:
throw 'cannot convert $exp yet';
};
#if test
trace(expr.expr);
#end
return expr;
}
static function readerExpToHaxeExpr(exp:ReaderExp, macros:Map<String, MacroFunction>, specialForms:Map<String, SpecialFormFunction>):Expr {
// Bind the table arguments of this function for easy recursive calling/passing
var convert = readerExpToHaxeExpr.bind(_, macros, specialForms);
var expr = switch (exp) {
case Symbol(name):
Context.parse(name, Context.currentPos());
case StrExp(s):
{
pos: Context.currentPos(),
expr: EConst(CString(s))
};
case CallExp(Symbol(mac), args) if (macros.exists(mac)):
convert(macros[mac](args));
case CallExp(Symbol(specialForm), args) if (specialForms.exists(specialForm)):
specialForms[specialForm](args, convert);
case CallExp(func, body):
{
pos: Context.currentPos(),
expr: ECall(readerExpToHaxeExpr(func, macros, specialForms), [for (bodyExp in body) readerExpToHaxeExpr(bodyExp, macros, specialForms)])
};
case ListExp(elements):
{
pos: Context.currentPos(),
expr: ENew({
pack: ["kiss"],
name: "List"
}, [
{
pos: Context.currentPos(),
expr: EArrayDecl([for (elementExp in elements) convert(elementExp)])
}
])
}
case RawHaxe(code):
Context.parse(code, Context.currentPos());
default:
throw 'cannot convert $exp yet';
};
#if test
trace(expr.expr);
#end
return expr;
}
}

View File

@@ -1,52 +1,52 @@
package kiss;
@:forward(length, concat, contains, copy, filter, indexOf, // insert is re-implemented with negative index support
iterator, join, keyValueIterator,
lastIndexOf, map, pop, push, remove, resize, reverse, shift, // slice is re-implemented with negative index support
sort,
// splice is re-implemented with negative index support,
toString, unshift)
iterator, join, keyValueIterator,
lastIndexOf, map, pop, push, remove, resize, reverse, shift, // slice is re-implemented with negative index support
sort,
// splice is re-implemented with negative index support,
toString, unshift)
abstract List<T>(Array<T>) from Array<T> to Array<T> {
public inline function new(a:Array<T>) {
this = a;
}
public inline function new(a:Array<T>) {
this = a;
}
@:from
static public function fromArray<T>(a:Array<T>) {
return new List<T>(a);
}
@:from
static public function fromArray<T>(a:Array<T>) {
return new List<T>(a);
}
@:to
public function toArray<T>() {
return this;
}
@:to
public function toArray<T>() {
return this;
}
inline function realIndex(idx:Int) {
return if (idx < 0) this.length + idx else idx;
}
inline function realIndex(idx:Int) {
return if (idx < 0) this.length + idx else idx;
}
@:arrayAccess
public inline function get<T>(idx:Int):Null<T> {
return this[realIndex(idx)];
}
@:arrayAccess
public inline function get<T>(idx:Int):Null<T> {
return this[realIndex(idx)];
}
@:arrayAccess
public inline function arrayWrite(idx:Int, v:T):T {
this[realIndex(idx)] = v;
return v;
}
@:arrayAccess
public inline function arrayWrite(idx:Int, v:T):T {
this[realIndex(idx)] = v;
return v;
}
public function insert(idx:Int, v:T) {
this.insert(realIndex(idx), v);
}
public function insert(idx:Int, v:T) {
this.insert(realIndex(idx), v);
}
public function slice(start:Int, ?end:Int) {
if (end == null)
end = this.length;
return this.slice(realIndex(start), realIndex(end));
}
public function slice(start:Int, ?end:Int) {
if (end == null)
end = this.length;
return this.slice(realIndex(start), realIndex(end));
}
public function splice(start:Int, len:Int) {
return this.splice(realIndex(start), len);
}
public function splice(start:Int, len:Int) {
return this.splice(realIndex(start), len);
}
}

View File

@@ -6,37 +6,37 @@ import kiss.Reader;
typedef MacroFunction = (Array<ReaderExp>) -> ReaderExp;
class Macros {
public static function builtins() {
var macros:Map<String, MacroFunction> = [];
public static function builtins() {
var macros:Map<String, MacroFunction> = [];
macros["+"] = foldMacro("Prelude.add");
macros["+"] = foldMacro("Prelude.add");
macros["-"] = foldMacro("Prelude.subtract");
macros["-"] = foldMacro("Prelude.subtract");
macros["*"] = foldMacro("Prelude.multiply");
macros["*"] = foldMacro("Prelude.multiply");
macros["/"] = foldMacro("Prelude.divide");
macros["/"] = foldMacro("Prelude.divide");
macros["%"] = (exps:Array<ReaderExp>) -> {
if (exps.length != 2) {
throw 'Got ${exps.length} arguments for % instead of 2.';
}
CallExp(Symbol("Prelude.mod"), [exps[1], exps[0]]);
};
macros["%"] = (exps:Array<ReaderExp>) -> {
if (exps.length != 2) {
throw 'Got ${exps.length} arguments for % instead of 2.';
}
CallExp(Symbol("Prelude.mod"), [exps[1], exps[0]]);
};
macros["^"] = (exps:Array<ReaderExp>) -> {
if (exps.length != 2) {
throw 'Got ${exps.length} arguments for ^ instead of 2.';
}
CallExp(Symbol("Prelude.pow"), [exps[1], exps[0]]);
};
macros["^"] = (exps:Array<ReaderExp>) -> {
if (exps.length != 2) {
throw 'Got ${exps.length} arguments for ^ instead of 2.';
}
CallExp(Symbol("Prelude.pow"), [exps[1], exps[0]]);
};
return macros;
}
return macros;
}
static function foldMacro(func:String):MacroFunction {
return (exps) -> {
CallExp(Symbol("Lambda.fold"), [ListExp(exps.slice(1)), Symbol(func), exps[0]]);
};
}
static function foldMacro(func:String):MacroFunction {
return (exps) -> {
CallExp(Symbol("Lambda.fold"), [ListExp(exps.slice(1)), Symbol(func), exps[0]]);
};
}
}

View File

@@ -1,27 +1,27 @@
package kiss;
class Prelude {
public static function add(a, b) {
return a + b;
}
public static function add(a, b) {
return a + b;
}
public static function subtract(val, from) {
return from - val;
}
public static function subtract(val, from) {
return from - val;
}
public static function multiply(a, b) {
return a * b;
}
public static function multiply(a, b) {
return a * b;
}
public static function divide(bottom:Float, top:Float) {
return top / bottom;
}
public static function divide(bottom:Float, top:Float) {
return top / bottom;
}
public static function mod(bottom, top) {
return top % bottom;
}
public static function mod(bottom, top) {
return top % bottom;
}
public static function pow(exponent, base) {
return Math.pow(base, exponent);
}
public static function pow(exponent, base) {
return Math.pow(base, exponent);
}
}

View File

@@ -4,76 +4,76 @@ import haxe.ds.Option;
import kiss.Stream;
enum ReaderExp {
CallExp(func:ReaderExp, args:Array<ReaderExp>); // (f a1 a2...)
ListExp(exps:Array<ReaderExp>); // [v1 v2 v3]
StrExp(s:String); // "literal"
Symbol(name:String); // s
RawHaxe(code:String);
CallExp(func:ReaderExp, args:Array<ReaderExp>); // (f a1 a2...)
ListExp(exps:Array<ReaderExp>); // [v1 v2 v3]
StrExp(s:String); // "literal"
Symbol(name:String); // s
RawHaxe(code:String);
}
typedef ReadFunction = (Stream) -> Null<ReaderExp>;
class Reader {
// The built-in readtable
public static function builtins() {
var readTable:Map<String, ReadFunction> = [];
// The built-in readtable
public static function builtins() {
var readTable:Map<String, ReadFunction> = [];
readTable["("] = (stream) -> CallExp(assertRead(stream, readTable), readExpArray(stream, ")", readTable));
readTable["["] = (stream) -> ListExp(readExpArray(stream, "]", readTable));
readTable["\""] = (stream) -> StrExp(stream.expect("closing \"", () -> stream.takeUntilAndDrop("\"")));
readTable["/*"] = (stream) -> {
stream.dropUntil("*/");
stream.dropString("*/");
null;
};
readTable["//"] = (stream) -> {
stream.dropUntil("\n");
null;
};
readTable["#|"] = (stream) -> RawHaxe(stream.expect("closing |", () -> stream.takeUntilAndDrop("|#")));
readTable["("] = (stream) -> CallExp(assertRead(stream, readTable), readExpArray(stream, ")", readTable));
readTable["["] = (stream) -> ListExp(readExpArray(stream, "]", readTable));
readTable["\""] = (stream) -> StrExp(stream.expect("closing \"", () -> stream.takeUntilAndDrop("\"")));
readTable["/*"] = (stream) -> {
stream.dropUntil("*/");
stream.dropString("*/");
null;
};
readTable["//"] = (stream) -> {
stream.dropUntil("\n");
null;
};
readTable["#|"] = (stream) -> RawHaxe(stream.expect("closing |", () -> stream.takeUntilAndDrop("|#")));
return readTable;
}
return readTable;
}
public static function assertRead(stream:Stream, readTable:Map<String, ReadFunction>):ReaderExp {
var position = stream.position();
return switch (read(stream, readTable)) {
case Some(exp):
exp;
case None:
throw 'There were no expressions left in the stream at $position';
};
}
public static function assertRead(stream:Stream, readTable:Map<String, ReadFunction>):ReaderExp {
var position = stream.position();
return switch (read(stream, readTable)) {
case Some(exp):
exp;
case None:
throw 'There were no expressions left in the stream at $position';
};
}
public static function read(stream:Stream, readTable:Map<String, ReadFunction>):Option<ReaderExp> {
stream.dropWhitespace();
public static function read(stream:Stream, readTable:Map<String, ReadFunction>):Option<ReaderExp> {
stream.dropWhitespace();
if (stream.isEmpty())
return None;
if (stream.isEmpty())
return None;
var readTableKeys = [for (key in readTable.keys()) key];
readTableKeys.sort((a, b) -> b.length - a.length);
var readTableKeys = [for (key in readTable.keys()) key];
readTableKeys.sort((a, b) -> b.length - a.length);
for (key in readTableKeys) {
switch (stream.peekChars(key.length)) {
case Some(k) if (k == key):
stream.dropString(key);
var expOrNull = readTable[key](stream);
return if (expOrNull != null) Some(expOrNull) else read(stream, readTable);
default:
}
}
for (key in readTableKeys) {
switch (stream.peekChars(key.length)) {
case Some(k) if (k == key):
stream.dropString(key);
var expOrNull = readTable[key](stream);
return if (expOrNull != null) Some(expOrNull) else read(stream, readTable);
default:
}
}
return Some(Symbol(stream.expect("a symbol name", () -> stream.takeUntilOneOf([")", "]", "/*", "\n", " "]))));
}
return Some(Symbol(stream.expect("a symbol name", () -> stream.takeUntilOneOf([")", "]", "/*", "\n", " "]))));
}
public static function readExpArray(stream:Stream, end:String, readTable:Map<String, ReadFunction>):Array<ReaderExp> {
var array = [];
while (stream.expect('$end to terminate list', () -> stream.peekChars(end.length)) != end) {
stream.dropWhitespace();
array.push(assertRead(stream, readTable));
}
stream.dropString(end);
return array;
}
public static function readExpArray(stream:Stream, end:String, readTable:Map<String, ReadFunction>):Array<ReaderExp> {
var array = [];
while (stream.expect('$end to terminate list', () -> stream.peekChars(end.length)) != end) {
stream.dropWhitespace();
array.push(assertRead(stream, readTable));
}
stream.dropString(end);
return array;
}
}

View File

@@ -9,19 +9,19 @@ import kiss.Types;
typedef SpecialFormFunction = (args:Array<ReaderExp>, convert:ExprConversion) -> Expr;
class SpecialForms {
public static function builtins() {
var map:Map<String, SpecialFormFunction> = [];
public static function builtins() {
var map:Map<String, SpecialFormFunction> = [];
map["begin"] = (args:Array<ReaderExp>, convert:ExprConversion) -> {
pos: Context.currentPos(),
expr: EBlock([for (bodyExp in args) convert(bodyExp)])
};
map["begin"] = (args:Array<ReaderExp>, convert:ExprConversion) -> {
pos: Context.currentPos(),
expr: EBlock([for (bodyExp in args) convert(bodyExp)])
};
map["nth"] = (args:Array<ReaderExp>, convert:ExprConversion) -> {
pos: Context.currentPos(),
expr: EArray(convert(args[0]), convert(args[1]))
};
map["nth"] = (args:Array<ReaderExp>, convert:ExprConversion) -> {
pos: Context.currentPos(),
expr: EArray(convert(args[0]), convert(args[1]))
};
return map;
}
return map;
}
}

View File

@@ -7,102 +7,102 @@ using StringTools;
using Lambda;
class Stream {
var content:String;
var file:String;
var line:Int;
var column:Int;
var content:String;
var file:String;
var line:Int;
var column:Int;
public function new(file:String) {
// Banish ye Windows line-endings
content = File.getContent(file).replace('\r', '');
// Life is easier with a trailing newline
if (content.charAt(content.length - 1) != "\n")
content += "\n";
public function new(file:String) {
// Banish ye Windows line-endings
content = File.getContent(file).replace('\r', '');
// Life is easier with a trailing newline
if (content.charAt(content.length - 1) != "\n")
content += "\n";
this.file = file;
line = 1;
column = 1;
}
this.file = file;
line = 1;
column = 1;
}
public function peekChars(chars:Int):Option<String> {
if (content.length < chars)
return None;
return Some(content.substr(0, chars));
}
public function peekChars(chars:Int):Option<String> {
if (content.length < chars)
return None;
return Some(content.substr(0, chars));
}
public function isEmpty() {
return content.length == 0;
}
public function isEmpty() {
return content.length == 0;
}
public function position() {
return '$file:$line:$column';
}
public function position() {
return '$file:$line:$column';
}
/** Every drop call should end up calling dropChars() or the position tracker will be wrong. **/
private function dropChars(count:Int) {
for (idx in 0...count) {
switch (content.charAt(idx)) {
case "\n":
line += 1;
column = 1;
default:
column += 1;
}
}
content = content.substr(count);
}
/** Every drop call should end up calling dropChars() or the position tracker will be wrong. **/
private function dropChars(count:Int) {
for (idx in 0...count) {
switch (content.charAt(idx)) {
case "\n":
line += 1;
column = 1;
default:
column += 1;
}
}
content = content.substr(count);
}
public function takeChars(count:Int):Option<String> {
if (count > content.length)
return None;
var toReturn = content.substr(0, count);
dropChars(count);
return Some(toReturn);
}
public function takeChars(count:Int):Option<String> {
if (count > content.length)
return None;
var toReturn = content.substr(0, count);
dropChars(count);
return Some(toReturn);
}
public function dropString(s:String) {
var toDrop = content.substr(0, s.length);
if (toDrop != s) {
throw 'Expected $s at ${position()}';
}
dropChars(s.length);
}
public function dropString(s:String) {
var toDrop = content.substr(0, s.length);
if (toDrop != s) {
throw 'Expected $s at ${position()}';
}
dropChars(s.length);
}
public function dropUntil(s:String) {
dropChars(content.indexOf(s));
}
public function dropUntil(s:String) {
dropChars(content.indexOf(s));
}
public function dropWhitespace() {
var trimmed = content.ltrim();
dropChars(content.length - trimmed.length);
}
public function dropWhitespace() {
var trimmed = content.ltrim();
dropChars(content.length - trimmed.length);
}
public function takeUntilOneOf(terminators:Array<String>):Option<String> {
var indices = [for (term in terminators) content.indexOf(term)].filter((idx) -> idx >= 0);
if (indices.length == 0)
return None;
var firstIndex = Math.floor(indices.fold(Math.min, indices[0]));
return takeChars(firstIndex);
}
public function takeUntilOneOf(terminators:Array<String>):Option<String> {
var indices = [for (term in terminators) content.indexOf(term)].filter((idx) -> idx >= 0);
if (indices.length == 0)
return None;
var firstIndex = Math.floor(indices.fold(Math.min, indices[0]));
return takeChars(firstIndex);
}
public function takeUntilAndDrop(s:String):Option<String> {
var idx = content.indexOf(s);
public function takeUntilAndDrop(s:String):Option<String> {
var idx = content.indexOf(s);
if (idx < 0)
return None;
if (idx < 0)
return None;
var toReturn = content.substr(0, idx);
dropChars(toReturn.length + s.length);
return Some(toReturn);
}
var toReturn = content.substr(0, idx);
dropChars(toReturn.length + s.length);
return Some(toReturn);
}
public function expect(whatToExpect:String, f:Void->Option<String>):String {
var position = position();
switch (f()) {
case Some(s):
return s;
case None:
throw 'Expected $whatToExpect at $position';
}
}
public function expect(whatToExpect:String, f:Void->Option<String>):String {
var position = position();
switch (f()) {
case Some(s):
return s;
case None:
throw 'Expected $whatToExpect at $position';
}
}
}

View File

@@ -4,10 +4,10 @@ import utest.Runner;
import utest.ui.Report;
class TestMain {
public static function main() {
var runner = new Runner();
runner.addCases(test.cases);
Report.create(runner);
runner.run();
}
public static function main() {
var runner = new Runner();
runner.addCases(test.cases);
Report.create(runner);
runner.run();
}
}

View File

@@ -6,72 +6,72 @@ import kiss.Prelude;
@:build(kiss.Kiss.build("src/test/cases/BasicTestCase.kiss"))
class BasicTestCase extends Test {
function testStaticVar() {
Assert.equals("Howdy", BasicTestCase.message);
}
function testStaticVar() {
Assert.equals("Howdy", BasicTestCase.message);
}
function testHaxeInsertion() {
Assert.equals(23, BasicTestCase.mathResult);
}
function testHaxeInsertion() {
Assert.equals(23, BasicTestCase.mathResult);
}
function testStaticFunction() {
Assert.equals(6, BasicTestCase.myFloor(6.5));
}
function testStaticFunction() {
Assert.equals(6, BasicTestCase.myFloor(6.5));
}
function testFuncall() {
Assert.equals(7, BasicTestCase.funResult);
}
function testFuncall() {
Assert.equals(7, BasicTestCase.funResult);
}
function testField() {
Assert.equals(5, new BasicTestCase().myField);
}
function testField() {
Assert.equals(5, new BasicTestCase().myField);
}
function testMethod() {
Assert.equals(5, new BasicTestCase().myMethod());
}
function testMethod() {
Assert.equals(5, new BasicTestCase().myMethod());
}
function testArray() {
var arr = BasicTestCase.myArray;
Assert.equals(3, arr.length);
Assert.equals(1, arr[0]);
Assert.equals(2, arr[1]);
Assert.equals(3, arr[2]);
function testArray() {
var arr = BasicTestCase.myArray;
Assert.equals(3, arr.length);
Assert.equals(1, arr[0]);
Assert.equals(2, arr[1]);
Assert.equals(3, arr[2]);
// Kiss arrays can be negatively indexed like Python
Assert.equals(3, arr[-1]);
Assert.equals(2, arr[-2]);
Assert.equals(1, arr[-3]);
}
// Kiss arrays can be negatively indexed like Python
Assert.equals(3, arr[-1]);
Assert.equals(2, arr[-2]);
Assert.equals(1, arr[-3]);
}
function testArrayAccess() {
Assert.equals(3, BasicTestCase.myArrayLast);
}
function testArrayAccess() {
Assert.equals(3, BasicTestCase.myArrayLast);
}
function testVariadicAdd() {
Assert.equals(6, BasicTestCase.mySum);
}
function testVariadicAdd() {
Assert.equals(6, BasicTestCase.mySum);
}
function testVariadicSubtract() {
Assert.equals(-2, BasicTestCase.myDifference);
}
function testVariadicSubtract() {
Assert.equals(-2, BasicTestCase.myDifference);
}
function testVariadicMultiply() {
Assert.equals(60, BasicTestCase.myProduct);
}
function testVariadicMultiply() {
Assert.equals(60, BasicTestCase.myProduct);
}
function testVariadicDivide() {
Assert.equals(0.5, BasicTestCase.myQuotient);
}
function testVariadicDivide() {
Assert.equals(0.5, BasicTestCase.myQuotient);
}
function testMod() {
Assert.equals(4, BasicTestCase.myRemainder);
}
function testMod() {
Assert.equals(4, BasicTestCase.myRemainder);
}
function testPow() {
Assert.equals(256, BasicTestCase.myPower);
}
function testPow() {
Assert.equals(256, BasicTestCase.myPower);
}
function testUnop() {
Assert.equals(7, BasicTestCase.myInc);
}
function testUnop() {
Assert.equals(7, BasicTestCase.myInc);
}
}