Skip to content

Commit

Permalink
Improve cli parser (#589)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored Jun 14, 2024
1 parent 62beaa9 commit f78370f
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 16 deletions.
17 changes: 9 additions & 8 deletions src/typechecker/TypeMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,15 @@ void TypeMatcher::substantiateTypeWithTypeMapping(QualType &type, const TypeMapp
// Only do this, if the struct or interface is not self-referencing, because in that case we'd end up in an infinite recursion
if (!baseType.isSelfReferencingStructType()) {
Scope *matchScope = baseType.getBodyScope()->parent;
StructBase *spiceStructBase;
if (baseType.is(TY_STRUCT)) // Struct
spiceStructBase = StructManager::matchStruct(matchScope, baseType.getSubType(), templateTypes, nullptr);
else // Interface
spiceStructBase = InterfaceManager::matchInterface(matchScope, baseType.getSubType(), templateTypes, nullptr);
assert(spiceStructBase != nullptr);
// Attach the body scope to the symbol type
type = type.getWithBodyScope(spiceStructBase->scope);
if (baseType.is(TY_STRUCT)) { // Struct
Struct *spiceStruct = StructManager::matchStruct(matchScope, baseType.getSubType(), templateTypes, nullptr);
assert(spiceStruct != nullptr);
type = type.getWithBodyScope(spiceStruct->scope);
} else { // Interface
Interface *spiceInterface = InterfaceManager::matchInterface(matchScope, baseType.getSubType(), templateTypes, nullptr);
assert(spiceInterface != nullptr);
type = type.getWithBodyScope(spiceInterface->scope);
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions std/io/cli-option.spice
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "std/os/os";
import "std/data/vector";

// Generic types
type T bool|string|int|long|short;
Expand All @@ -9,6 +10,7 @@ type CliOptionMode enum { SET_VALUE, CALL_CALLBACK }
public type CliOption<T> struct {
string name
string description
Vector<string> aliases
CliOptionMode mode
T& targetVariable
p(T&) callback
Expand Down Expand Up @@ -36,6 +38,14 @@ public f<string> CliOption.getDescription() {
return this.description;
}

public p CliOption.addAlias(string optionName) {
this.aliases.pushBack(optionName);
}

public f<const Vector<string>&> CliOption.getAliases() {
return this.aliases;
}

public p CliOption.setTargetValue(T value) {
if this.mode == CliOptionMode::SET_VALUE {
this.targetVariable = value;
Expand Down
29 changes: 21 additions & 8 deletions std/io/cli-subcommand.spice
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public type CliSubcommand struct {
string versionString
string footer = ""
p() callback
Vector<string> aliases
Vector<CliSubcommand> subcommands
Vector<CliOption<bool>> boolOptions
Vector<CliOption<string>> stringOptions
Expand All @@ -26,10 +27,18 @@ public p CliSubcommand.ctor(CliSubcommand* parent, string versionString, string
this.description = description;
this.versionString = versionString;
this.parent = parent;
this.subcommands = Vector<CliSubcommand>();
this.boolOptions = Vector<CliOption<bool>>();
this.stringOptions = Vector<CliOption<string>>();
this.intOptions = Vector<CliOption<int>>();
}

f<bool> CliSubcommand.nameOrAliasMatches(string name, const Vector<string>& aliases, string input) {
if name == input {
return true;
}
foreach const string a : aliases {
if a == input {
return true;
}
}
return false;
}

public f<int> CliSubcommand.parse(unsigned int argc, string[] argv, int layer = 1) {
Expand All @@ -49,7 +58,7 @@ public f<int> CliSubcommand.parse(unsigned int argc, string[] argv, int layer =

// Check for subcommands
foreach const CliSubcommand& subcommand : this.subcommands {
if arg == subcommand.getName() {
if this.nameOrAliasMatches(subcommand.getName(), subcommand.aliases, arg) {
return subcommand.parse(argc, argv, layer + 1);
}
}
Expand All @@ -66,15 +75,15 @@ public f<int> CliSubcommand.parse(unsigned int argc, string[] argv, int layer =

// Check for options
foreach const CliOption<bool>& boolOption : this.boolOptions {
if arg == boolOption.getName() {
if this.nameOrAliasMatches(boolOption.getName(), boolOption.getAliases(), arg) {
bool value = true;
boolOption.setTargetValue(value);
boolOption.callCallback(value);
continue 2; // Continue with next argument
}
}
foreach const CliOption<string>& stringOption : this.stringOptions {
if arg == stringOption.getName() {
if this.nameOrAliasMatches(stringOption.getName(), stringOption.getAliases(), arg) {
// get the argument value
arg = argv[++argNo];

Expand All @@ -84,7 +93,7 @@ public f<int> CliSubcommand.parse(unsigned int argc, string[] argv, int layer =
}
}
foreach const CliOption<int>& intOption : this.intOptions {
if arg == intOption.getName() {
if this.nameOrAliasMatches(intOption.getName(), intOption.getAliases(), arg) {
// get the argument value
arg = argv[++argNo];
int parsedArg = toInt(arg);
Expand Down Expand Up @@ -132,6 +141,10 @@ public p CliSubcommand.allowUnknownOptions() {
}
}

public p CliSubcommand.addAlias(string subCommand) {
this.aliases.pushBack(subCommand);
}

public f<CliSubcommand&> CliSubcommand.addSubcommand(string name, string description) {
this.subcommands.pushBack(CliSubcommand(this, this.versionString, name, description));
return this.subcommands.back();
Expand Down

0 comments on commit f78370f

Please sign in to comment.