JS: A working v0.9.0
This commit is contained in:
parent
f614b8db20
commit
a1b8bc4630
5 changed files with 261 additions and 216 deletions
112
assets/js/command.js
Normal file
112
assets/js/command.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
import { NameTerm, NumberTerm } from "./terms.js";
|
||||
|
||||
class ParseCommandError extends SyntaxError { }
|
||||
|
||||
class Parameter {
|
||||
name;
|
||||
value;
|
||||
|
||||
constructor(name, value) {
|
||||
if (!name instanceof NameTerm) {
|
||||
throw new TypeError("Parameter name must be a NameTerm");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.value ? `${this.name}=${this.value}` : `${this.name}`;
|
||||
}
|
||||
|
||||
valueOf() {
|
||||
if (this.value !== undefined) {
|
||||
return this.value.valueOf();
|
||||
} else {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Command {
|
||||
static stringRegex = /'[^'"]*'|"[^'"]*"/;
|
||||
static whitespaceRegex = /\s+/;
|
||||
|
||||
static parse(commandString) {
|
||||
const terms = commandString.split(Command.whitespaceRegex).filter(s => !!s);
|
||||
|
||||
if (terms.length < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let verb;
|
||||
try {
|
||||
verb = new NameTerm(terms[0]);
|
||||
} catch {
|
||||
throw new ParseCommandError(`Invalid verb: ${verb}`);
|
||||
}
|
||||
|
||||
const parameters = terms.slice(1).map(t => {
|
||||
const [nameString, valueString, ...rest] = t.split("=");
|
||||
|
||||
if (rest.length > 0) {
|
||||
throw new ParseCommandError(`Invalid parameter: ${t}`);
|
||||
}
|
||||
|
||||
let name;
|
||||
try {
|
||||
name = new NameTerm(nameString);
|
||||
} catch {
|
||||
throw new ParseCommandError(`Invalid parameter name: ${t}`);
|
||||
}
|
||||
|
||||
let value;
|
||||
if (valueString) {
|
||||
for (const termClass of [NameTerm, NumberTerm]) {
|
||||
try {
|
||||
value = new termClass(valueString);
|
||||
break;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
throw new ParseCommandError(`Invalid parameter value: ${t}`);
|
||||
}
|
||||
}
|
||||
|
||||
return new Parameter(name, value);
|
||||
});
|
||||
|
||||
return new Command(commandString, verb, parameters);
|
||||
}
|
||||
|
||||
originalString;
|
||||
verb;
|
||||
parameters = []
|
||||
|
||||
constructor(originalString, verb, parameters) {
|
||||
if (!verb instanceof String) {
|
||||
throw new TypeError("Command verb must be a string");
|
||||
}
|
||||
|
||||
this.originalString = originalString;
|
||||
this.verb = verb;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
parameter(nameOrIndex) {
|
||||
if (typeof nameOrIndex === "string" || nameOrIndex instanceof String) {
|
||||
return this.parameters.find(p => p.name == nameOrIndex);
|
||||
} else if (nameOrIndex instanceof Number) {
|
||||
return this.parameters[nameOrIndex].valueOf();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `Command: {verb: "${this.verb.toString()}", parameters: [${this.parameters.join(", ")}] }`;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue