Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added StrintToInt(Start|End) commands #570

Merged
merged 1 commit into from
Nov 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* [Strings](docs/syntax/strings.md)
* [Variables](docs/syntax/variables.md)
* [Math](docs/syntax/math.md)
* [String Conversions](docs/syntax/math/string-conversions.md)
* [Arrays and Lists](docs/syntax/arrays-and-lists.md)
* [Dictionaries](docs/syntax/dictionaries.md)
* [Classes](docs/syntax/classes.md)
Expand Down
62 changes: 62 additions & 0 deletions docs/syntax/math/string-conversions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# String Conversions

You can attempt to convert from raw strings to doubles or ints.
Different languages expose vastly different behaviors around cases where the numbers cannot be converted,
so blocks of code that rely on converted numbers are structured similarly to `if start` statements.

Use `if string to double start` and `if string to int start` to convert string(s) to double(s) or int(s), respectively.
Each takes in any number of repeating parameters: a string to convert and the numeric type to try to store it in.
Code before the next respective `if string to double end` or `if string to int end` will run only if the conversion was successful.

```gls
if string to double start : "3.5" asDouble
comment line : ...
if string to double end

variable : secondIntRaw string "14"
if string to int start : "7" firstInt secondIntRaw secondInt
comment line : ...
if string to int end
```

C#:

```csharp
if (double.TryParse("3.5", out var asDouble))
{
// ...
}

string secondIntRaw = "14";
if (int.TryParse("7", out var firstInt) && int.TryParse(secondIntRaw, out var secondInt))
{
// ...
}
```

Python:

```python
asDouble = None

try:
asDouble = float("3.5")
except:
pass

if asDouble is not None:
# ...

secondIntRaw = "14"
firstInt = None
secondInt = None

try:
firstInt = int("7")
secondInt = int(secondIntRaw)
except:
pass

if firstInt is not None and secondInt is not None:
# ...
```
4 changes: 4 additions & 0 deletions src/Rendering/Commands/CommandsBagFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import { IfEndCommand } from "./IfEndCommand";
import { IfStartCommand } from "./IfStartCommand";
import { IfStringToDoubleEndCommand } from "./IfStringToDoubleEndCommand";
import { IfStringToDoubleStartCommand } from "./IfStringToDoubleStartCommand";
import { IfStringToIntEndCommand } from "./IfStringToIntEndCommand";
import { IfStringToIntStartCommand } from "./IfStringToIntStartCommand";
import { ImportLocalCommand } from "./ImportLocalCommand";
import { ImportPackageCommand } from "./ImportPackageCommand";
import { ImportStandaloneFunctionsCommand } from "./ImportStandaloneFunctionsCommand";
Expand Down Expand Up @@ -209,6 +211,8 @@ export class CommandsBagFactory {
new IfStartCommand(context),
new IfStringToDoubleEndCommand(context),
new IfStringToDoubleStartCommand(context),
new IfStringToIntEndCommand(context),
new IfStringToIntStartCommand(context),
new ImportLocalCommand(context),
new ImportPackageCommand(context),
new ImportStandaloneFunctionsCommand(context),
Expand Down
27 changes: 4 additions & 23 deletions src/Rendering/Commands/IfStringToDoubleStartCommand.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GlsUtilities } from "../../GlsUtilities";
import { StringToNumberStartConversionType } from "../Languages/Properties/Syntax/StringToNumberSyntax";
import { LineResults } from "../LineResults";
import { CommandNames } from "../Names/CommandNames";
import { KeywordNames } from "../Names/KeywordNames";
Expand All @@ -8,26 +9,6 @@ import { CommandMetadata } from "./Metadata/CommandMetadata";
import { SingleParameter } from "./Metadata/Parameters/SingleParameter";
import { addLineEnder } from "./Utilities";

/**
* How a language attempts to convert strings to doubles.
*/
export enum StringToDoubleStartConversionType {
/**
* Convert strings into double variables and validate the results.
*/
ConvertAndValidate = "ConvertAndValidate",

/**
* Declare double variables, convert strings into them, and validate the results.
*/
PredeclareConvertAndValidate = "PredeclareConvertAndValidate",

/**
* Directly validate calls to double conversions inline.
*/
ValidateDirectly = "ValidateDirectly",
}

/**
* Starts a block to be executed if a string can be converted to a double.
*/
Expand Down Expand Up @@ -57,14 +38,14 @@ export class IfStringToDoubleStartCommand extends Command {
* @returns Line(s) of code in the language.
*/
public render(parameters: string[]): LineResults {
const conversionType: StringToDoubleStartConversionType = this.language.syntax.strings.toDouble.conversionType;
const conversionType: StringToNumberStartConversionType = this.language.syntax.strings.toDouble.conversionType;
const lines: CommandResult[] = [];

if (conversionType === StringToDoubleStartConversionType.PredeclareConvertAndValidate) {
if (conversionType === StringToNumberStartConversionType.PredeclareConvertAndValidate) {
this.predeclareVariables(parameters, lines);
}

if (conversionType !== StringToDoubleStartConversionType.ValidateDirectly) {
if (conversionType !== StringToNumberStartConversionType.ValidateDirectly) {
this.convertStrings(parameters, lines);
}

Expand Down
22 changes: 22 additions & 0 deletions src/Rendering/Commands/IfStringToIntEndCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CommandNames } from "../Names/CommandNames";
import { BlockEndCommand } from "./BlockEndCommand";
import { CommandMetadata } from "./Metadata/CommandMetadata";

/**
* Ends a block to be executed if a string can be converted to a int.
*/
export class IfStringToIntEndCommand extends BlockEndCommand {
/**
* Metadata on the command.
*/
private static metadata: CommandMetadata = new CommandMetadata(CommandNames.IfStringToIntEnd)
.withDescription("Ends a block to be executed if a string can be converted to a int")
.withIndentation([-1]);

/**
* @returns Metadata on the command.
*/
public getMetadata(): CommandMetadata {
return IfStringToIntEndCommand.metadata;
}
}
140 changes: 140 additions & 0 deletions src/Rendering/Commands/IfStringToIntStartCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { GlsUtilities } from "../../GlsUtilities";
import { StringToNumberStartConversionType } from "../Languages/Properties/Syntax/StringToNumberSyntax";
import { LineResults } from "../LineResults";
import { CommandNames } from "../Names/CommandNames";
import { KeywordNames } from "../Names/KeywordNames";
import { Command } from "./Command";
import { CommandResult } from "./CommandResult";
import { CommandMetadata } from "./Metadata/CommandMetadata";
import { SingleParameter } from "./Metadata/Parameters/SingleParameter";
import { addLineEnder } from "./Utilities";

/**
* Starts a block to be executed if a string can be converted to a int.
*/
export class IfStringToIntStartCommand extends Command {
/**
* Metadata on the command.
*/
private static metadata: CommandMetadata = new CommandMetadata(CommandNames.IfStringToIntStart)
.withDescription("Starts a block to be executed if a string can be converted to a int")
.withIndentation([1])
.withParameters([
new SingleParameter("stringName", "Name of a string to try converting.", true),
new SingleParameter("intName", "What to call the string in int form.", true),
]);

/**
* @returns Metadata on the command.
*/
public getMetadata(): CommandMetadata {
return IfStringToIntStartCommand.metadata;
}

/**
* Renders the command for a language with the given parameters.
*
* @param parameters The command's name, followed by any parameters.
* @returns Line(s) of code in the language.
*/
public render(parameters: string[]): LineResults {
const conversionType: StringToNumberStartConversionType = this.language.syntax.strings.toInt.conversionType;
const lines: CommandResult[] = [];

if (conversionType === StringToNumberStartConversionType.PredeclareConvertAndValidate) {
this.predeclareVariables(parameters, lines);
}

if (conversionType !== StringToNumberStartConversionType.ValidateDirectly) {
this.convertStrings(parameters, lines);
}

this.validateInts(parameters, lines);

const results: LineResults = new LineResults(lines);

results.withImports(this.language.syntax.strings.toInt.requiredImports);
results.commandResults[results.commandResults.length - 1].indentation = 1;

return results;
}

/**
* Adds pre-declared variables to the output lines.
*
* @param parameters The command's name, followed by any parameters.
* @param lines Output lines of rendered language code.
*/
private predeclareVariables(parameters: string[], lines: CommandResult[]): void {
const initialValue = this.language.syntax.strings.toInt.initialVariableValues;

for (let i = 1; i < parameters.length; i += 2) {
const declarationParameters: string[] = [CommandNames.Variable, parameters[i + 1], KeywordNames.Int];

if (initialValue !== "") {
declarationParameters.push(initialValue);
}

const declaration = this.context.convertParsed(declarationParameters).commandResults[0];
declaration.text += this.language.syntax.style.semicolon;
lines.push(declaration);
}

addLineEnder(lines, this.language.syntax.strings.toInt.initializeVariablesEnd, 0);
}

/**
* Adds string-to-int conversions to the output lines.
*
* @param parameters The command's name, followed by any parameters.
* @param lines Output lines of rendered language code.
*/
private convertStrings(parameters: string[], lines: CommandResult[]): void {
if (lines.length === 0) {
lines.push(new CommandResult("", 0));
}

for (let i = 1; i < parameters.length; i += 2) {
const stringName = parameters[i];
const intName = parameters[i + 1];

addLineEnder(lines, this.language.syntax.strings.toInt.perVariableConversionStartLeft, 0);
addLineEnder(lines, intName, 0);
addLineEnder(lines, this.language.syntax.strings.toInt.perVariableConversionStartMiddle, 0);
addLineEnder(lines, stringName, 0);
addLineEnder(lines, this.language.syntax.strings.toInt.perVariableConversionStartRight, 0);
}
}

/**
* Adds int validation checks to the output lines.
*
* @param parameters The command's name, followed by any parameters.
* @param lines Output lines of rendered language code.
*/
private validateInts(parameters: string[], lines: CommandResult[]): void {
if (lines.length === 0) {
lines.push(new CommandResult("", 0));
}

addLineEnder(lines, this.language.syntax.strings.toInt.validationBlockLeft, 0);

for (let i = 1; i < parameters.length; i += 2) {
const stringName = parameters[i];
const intName = parameters[i + 1];

let comparison = this.language.syntax.strings.toInt.validationBlockComparison;

comparison = GlsUtilities.stringReplaceAll(comparison, "{0}", stringName);
comparison = GlsUtilities.stringReplaceAll(comparison, "{1}", intName);

addLineEnder(lines, comparison, 0);

if (i < parameters.length - 2) {
addLineEnder(lines, this.language.syntax.strings.toInt.validationBlockMiddle, 0);
}
}

addLineEnder(lines, this.language.syntax.strings.toInt.validationBlockRight, 0);
}
}
2 changes: 1 addition & 1 deletion src/Rendering/Commands/ImportStandaloneFunctionsCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class ImportStandaloneFunctionsCommand extends Command {
public render(parameters: string[]): LineResults {
const importParameters: string[] = this.getImportParameters(parameters);

return LineResults.newSingleLine(importParameters.join(" "));
return LineResults.newSingleLine(importParameters.join(", "));
}

private getImportParameters(parameters: string[]): string[] {
Expand Down
23 changes: 17 additions & 6 deletions src/Rendering/Languages/CSharp.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { StringToDoubleStartConversionType } from "../Commands/IfStringToDoubleStartCommand";
import { CaseStyle } from "./Casing/CaseStyle";
import { Import } from "./Imports/Import";
import { ImportRelativity } from "./Imports/ImportRelativity";
Expand Down Expand Up @@ -40,7 +39,7 @@ import { StandaloneFunctionSyntax } from "./Properties/Syntax/StandaloneFunction
import { StringFormatSyntax } from "./Properties/Syntax/StringFormatSyntax";
import { StringSubstringSupport, StringSubstringSyntax } from "./Properties/Syntax/StringSubstringSyntax";
import { StringSyntax } from "./Properties/Syntax/StringSyntax";
import { StringToDoubleSyntax } from "./Properties/Syntax/StringToDoubleSyntax";
import { StringToNumberStartConversionType, StringToNumberSyntax } from "./Properties/Syntax/StringToNumberSyntax";
import { StyleSyntax } from "./Properties/Syntax/StyleSyntax";
import { UnsupportedSyntax } from "./Properties/Syntax/UnsupportedSyntax";
import { VariableSyntax } from "./Properties/Syntax/VariableSyntax";
Expand Down Expand Up @@ -703,17 +702,29 @@ export class CSharp extends Language {
*
* @param toDouble A property container for metadata on string-to-double conversions.
*/
protected generateStringToDoubleSyntax(toDouble: StringToDoubleSyntax): void {
toDouble.conversionType = StringToDoubleStartConversionType.ValidateDirectly;

protected generateStringToDoubleSyntax(toDouble: StringToNumberSyntax): void {
toDouble.conversionType = StringToNumberStartConversionType.ValidateDirectly;
toDouble.requiredImports = [new Import(["System"], ["Double"], ImportRelativity.Absolute)];

toDouble.validationBlockComparison = "double.TryParse({0}, out var {1})";
toDouble.validationBlockLeft = "if (";
toDouble.validationBlockMiddle = " && ";
toDouble.validationBlockRight = ")\n{";
}

/**
* Generates metadata on string-to-double conversions.
*
* @param toInt A property container for metadata on string-to-double conversions.
*/
protected generateStringToIntSyntax(toInt: StringToNumberSyntax): void {
toInt.conversionType = StringToNumberStartConversionType.ValidateDirectly;
toInt.requiredImports = [new Import(["System"], ["Int"], ImportRelativity.Absolute)];
toInt.validationBlockComparison = "int.TryParse({0}, out var {1})";
toInt.validationBlockLeft = "if (";
toInt.validationBlockMiddle = " && ";
toInt.validationBlockRight = ")\n{";
}

/**
* Generates metadata on style.
*
Expand Down
Loading