added cli arg parser
This commit is contained in:
parent
1108eab403
commit
5f42941d76
27
src/lib/args/ArgType.hx
Normal file
27
src/lib/args/ArgType.hx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package lib.args;
|
||||||
|
|
||||||
|
enum ArgType {
|
||||||
|
/** Any Int **/
|
||||||
|
Int(name:String);
|
||||||
|
|
||||||
|
/** Any Float **/
|
||||||
|
Float(name:String);
|
||||||
|
|
||||||
|
/** Any String **/
|
||||||
|
String(name:String);
|
||||||
|
|
||||||
|
/** A side like front, back, top, ... **/
|
||||||
|
Side(name:String);
|
||||||
|
|
||||||
|
/** Any peripheral address that exists **/
|
||||||
|
Addr(name:String);
|
||||||
|
|
||||||
|
/** Address of peripheral with given type **/
|
||||||
|
Peripheral(name:String, type:String);
|
||||||
|
|
||||||
|
/** An optional argument **/
|
||||||
|
Optional(type:ArgType);
|
||||||
|
|
||||||
|
/** The rest of the arguments as a string array **/
|
||||||
|
Rest(name:String);
|
||||||
|
}
|
181
src/lib/args/CLIArgs.hx
Normal file
181
src/lib/args/CLIArgs.hx
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
package lib.args;
|
||||||
|
|
||||||
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
|
import haxe.ds.ReadOnlyArray;
|
||||||
|
import haxe.ds.StringMap;
|
||||||
|
|
||||||
|
class CLIArgs {
|
||||||
|
private final argTypes:Array<ArgType>;
|
||||||
|
private final parsedArgs:StringMap<Dynamic> = new StringMap();
|
||||||
|
private var rest:Array<String>;
|
||||||
|
|
||||||
|
private var error:Null<String>;
|
||||||
|
private var errorPos:Int = 0;
|
||||||
|
|
||||||
|
public function new(args:Array<ArgType>) {
|
||||||
|
this.argTypes = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse(args:ReadOnlyArray<String>):Bool {
|
||||||
|
for (i => type in this.argTypes) {
|
||||||
|
if (args.length < (i + 1)) {
|
||||||
|
if (type.match(Optional(_))) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
this.errorPos = i;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case Rest(_):
|
||||||
|
this.rest = args.slice(i);
|
||||||
|
default:
|
||||||
|
if (!parseArg(args[i], type)) {
|
||||||
|
this.errorPos = i;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getError():String {
|
||||||
|
return 'Error at pos ${this.errorPos}: ${this.error}';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns synopsis.
|
||||||
|
**/
|
||||||
|
public static function getSynopsis(argTypes:Array<ArgType>):String {
|
||||||
|
var synopsis = "";
|
||||||
|
for (arg in argTypes) {
|
||||||
|
var name = getName(arg);
|
||||||
|
|
||||||
|
synopsis += switch (arg) {
|
||||||
|
case Optional(_): '[$name]';
|
||||||
|
case Rest(_): '[$name...]'; // TODO: is rest always optional?
|
||||||
|
default: '<$name>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return synopsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getName(arg:ArgType):String {
|
||||||
|
return switch (arg) {
|
||||||
|
case Int(name): name;
|
||||||
|
case Float(name): name;
|
||||||
|
case String(name): name;
|
||||||
|
case Side(name): name;
|
||||||
|
case Addr(name): name;
|
||||||
|
case Peripheral(name, type): name;
|
||||||
|
case Rest(name): name;
|
||||||
|
case Optional(type): getName(type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseArg(arg:String, type:ArgType):Bool {
|
||||||
|
switch type {
|
||||||
|
case Int(name):
|
||||||
|
var parsed = Std.parseInt(arg);
|
||||||
|
if (parsed == null) {
|
||||||
|
this.error = 'Need to be an integer';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parsedArgs.set(name, parsed);
|
||||||
|
case Float(name):
|
||||||
|
var parsed = Std.parseFloat(arg);
|
||||||
|
if (parsed == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parsedArgs.set(name, parsed);
|
||||||
|
case String(name):
|
||||||
|
this.parsedArgs.set(name, arg);
|
||||||
|
case Side(name):
|
||||||
|
if (!["front", "back", "top", "right", "left", "bottom"].contains(arg)) {
|
||||||
|
this.error = "must be a side";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parsedArgs.set(name, arg);
|
||||||
|
case Addr(name):
|
||||||
|
if (!Peripheral.isPresent(arg)) {
|
||||||
|
this.error = "address not present";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parsedArgs.set(name, arg);
|
||||||
|
case Peripheral(name, type):
|
||||||
|
if (!Peripheral.getTypes(arg).contains(type)) {
|
||||||
|
this.error = "address has invalid type";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parsedArgs.set(name, arg);
|
||||||
|
case Optional(innerType):
|
||||||
|
return parseArg(arg, innerType);
|
||||||
|
case Rest(name):
|
||||||
|
return true; // Should never happen
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the arg with `name`.
|
||||||
|
When in debug mode will throw execption on wrong type.
|
||||||
|
Returns null when not existing.
|
||||||
|
**/
|
||||||
|
public function getInt(name:String):Null<Int> {
|
||||||
|
var v = this.parsedArgs.get(name);
|
||||||
|
if (v == null)
|
||||||
|
return null;
|
||||||
|
#if debug
|
||||||
|
return cast(v, Int);
|
||||||
|
#else
|
||||||
|
return cast v;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the arg with `name`.
|
||||||
|
When in debug mode will throw execption on wrong type.
|
||||||
|
Returns null when not existing.
|
||||||
|
**/
|
||||||
|
public function getFloat(name:String):Null<Float> {
|
||||||
|
var v = this.parsedArgs.get(name);
|
||||||
|
if (v == null)
|
||||||
|
return null;
|
||||||
|
#if debug
|
||||||
|
return cast(v, Float);
|
||||||
|
#else
|
||||||
|
return cast v;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the arg with `name`.
|
||||||
|
When in debug mode will throw execption on wrong type.
|
||||||
|
Returns null when not existing.
|
||||||
|
**/
|
||||||
|
public function getString(name:String):Null<String> {
|
||||||
|
var v = this.parsedArgs.get(name);
|
||||||
|
if (v == null)
|
||||||
|
return null;
|
||||||
|
#if debug
|
||||||
|
return cast(v, String);
|
||||||
|
#else
|
||||||
|
return cast v;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if arg is present. Only makes sense on Optional args.
|
||||||
|
**/
|
||||||
|
public function hasArg(name:String):Bool {
|
||||||
|
return this.parsedArgs.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRest():Array<String> {
|
||||||
|
return this.rest;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user