Skip to content

Commit

Permalink
Move utlitity functions to separate class
Browse files Browse the repository at this point in the history
Signed-off-by: Tomas Slusny <[email protected]>
  • Loading branch information
deathbeam committed Feb 13, 2017
1 parent 23edf51 commit c5f0fb8
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 164 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ with a boolean `status` flag, indicating whether the parse succeeded. If it succ
contain the yielded value. Otherwise, the `index` and `expected` attributes will contain the offset of the parse error,
and a sorted, unique array of messages indicating what was expected.

The error object can be passed along with the original source to `Parser.formatError` to obtain
The error object can be passed along with the original source to `ParseUtil.formatError` to obtain
a human-readable error string.

Changing `ParseObject.apply` value changes `ParseObject` behaviour, but still keeps it's reference, what is
Expand Down
9 changes: 5 additions & 4 deletions src/parsihax/ParseObject.hx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import haxe.ds.Vector;
`var result = SomeParseObject.apply('Me Me Me! Parse Me!');`
**/
abstract ParseObject<T>(Vector<ParseFunction<T>>) {

inline function new() this = new Vector(1);
@:to inline function get_apply() : ParseFunction<T> return this[0];
inline function set_apply(param : ParseFunction<T>) return this[0] = param;
Expand All @@ -25,7 +26,7 @@ abstract ParseObject<T>(Vector<ParseFunction<T>>) {
/**
Creates `ParseObject` from `ParseFunction`
**/
@:noUsing @:from static inline public function to<T>(v : ParseFunction<T>) : ParseObject<T> {
@:noUsing @:from public static inline function to<T>(v : ParseFunction<T>) : ParseObject<T> {
var ret = new ParseObject();
ret.apply = v;
return ret;
Expand All @@ -34,21 +35,21 @@ abstract ParseObject<T>(Vector<ParseFunction<T>>) {
/**
Same as `Hax.then(l, r)`
**/
@:noUsing @:op(A + B) static inline public function opAdd<A, B>(l: ParseObject<A>, r: ParseObject<B>): ParseObject<B> {
@:noUsing @:op(A + B) public static inline function opAdd<A, B>(l: ParseObject<A>, r: ParseObject<B>): ParseObject<B> {
return Parser.then(l, r);
}

/**
Same as `Hax.or(l, r)`
**/
@:noUsing @:op(A | B) static inline public function opOr<A>(l: ParseObject<A>, r: ParseObject<A>): ParseObject<A> {
@:noUsing @:op(A | B) public static inline function opOr<A>(l: ParseObject<A>, r: ParseObject<A>): ParseObject<A> {
return Parser.or(l, r);
}

/**
Same as `Hax.as(l, r)`
**/
@:noUsing @:op(A / B) static inline public function opDiv<A>(l: ParseObject<A>, r: String): ParseObject<A> {
@:noUsing @:op(A / B) public static inline function opDiv<A>(l: ParseObject<A>, r: String): ParseObject<A> {
return Parser.as(l, r);
}

Expand Down
2 changes: 2 additions & 0 deletions src/parsihax/ParseResult.hx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package parsihax;
`Parser.formatError` to obtain a human-readable error string.
**/
typedef ParseResult<T> = {

/**
Flag, indicating whether the parse succeeded
**/
Expand All @@ -35,4 +36,5 @@ typedef ParseResult<T> = {
A sorted, unique array of messages indicating what was expected (in case of failed parse)
**/
var expected : Array<String>;

}
107 changes: 107 additions & 0 deletions src/parsihax/ParseUtil.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package parsihax;

class ParseUtil {

/**
Obtain a human-readable error `String`.
**/
public static function formatError<T>(result : ParseResult<T>, stream : String) : String {
var sexpected = result.expected.length == 1
? result.expected[0]
: 'one of ' + result.expected.join(', ');

var indexOffset = result.furthest;
var lines = stream.substring(0, indexOffset).split("\n");
var lineWeAreUpTo = lines.length;
var columnWeAreUpTo = lines[lines.length - 1].length + 1;

var got = '';

if (indexOffset == stream.length) {
got = ', got the end of the stream';
} else {
var prefix = (indexOffset > 0 ? "'..." : "'");
var suffix = (stream.length - indexOffset > 12 ? "...'" : "'");

got = ' at line ' + lineWeAreUpTo + ' column ' + columnWeAreUpTo
+ ', got ' + prefix + stream.substring(indexOffset, indexOffset + 12) + suffix;
}

return 'expected ' + sexpected + got;
}

/**
Create successfull `ParseResult` with specified `index` and `value`.
**/
@:allow(parsihax.Parser)
private static inline function makeSuccess<A>(index : Int, value : A) : ParseResult<A> {
return {
status: true,
index: index,
value: value,
furthest: -1,
expected: []
};
}

/**
Create failed `ParseResult` with specified `index` and `expected` input.
**/
@:allow(parsihax.Parser)
private static inline function makeFailure<A>(index : Int, expected : String) : ParseResult<A> {
return {
status: false,
index: -1,
value: null,
furthest: index,
expected: [expected]
};
}

/**
Merge `result` and `last` into single `ParseResult`.
**/
@:allow(parsihax.Parser)
private static function mergeReplies<A, B>(result : ParseResult<A>, ?last : ParseResult<B>) : ParseResult<A> {
if (last == null) return result;
if (result.furthest > last.furthest) return result;

var expected = (result.furthest == last.furthest)
? unsafeUnion(result.expected, last.expected)
: last.expected;

return {
status: result.status,
index: result.index,
value: result.value,
furthest: last.furthest,
expected: expected
}
}

/**
Create unsafe union from two string arrays `xs` and `ys`.
**/
private static function unsafeUnion(xs : Array<String>, ys : Array<String>) : Array<String> {
if (xs.length == 0) {
return ys;
} else if (ys.length == 0) {
return xs;
}

var result = xs.concat(ys);

result.sort(function(a, b):Int {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
});

return result;
}

}


Loading

0 comments on commit c5f0fb8

Please sign in to comment.