"Case must be a string or an integral constant" error? - switch-statement

OK, so here's my code :
//================================================
// Constants
//================================================
const string YAML_STRING = "tag:yaml.org,2002:str";
const string YAML_INT = "tag:yaml.org,2002:int";
const string YAML_FLOAT = "tag:yaml.org,2002:float";
const string YAML_BOOL = "tag:yaml.org,2002:bool";
const string YAML_SEQ = "tag:yaml.org,2002:seq";
const string YAML_SET = "tag:yaml.org,2002:set";
const string YAML_MAP = "tag:yaml.org,2002:map";
const string YAML_OMAP = "tag:yaml.org,2002:omap";
const string YAML_PAIRS = "tag:yaml.org,2002:pairs";
//================================================
// Functions
//================================================
Value parseYAMLNode(Node n)
{
writeln(n.tag);
switch (n.tag)
{
case YAML_STRING : return new Value(n.as!(string));
case YAML_INT : return new Value(n.as!(long));
case YAML_FLOAT : return new Value(n.as!(float));
case YAML_BOOL : return new Value(n.as!(bool));
default :
}
// more code - omitted
}
Once I decided to declare my case strings as consts (they are re-used, so I thought that'd be practical), it triggers a Case must be a string or an integral constant error.
Why is that? How can this be fixed?

OK, so here's what I came up with...
if constants are declared like :
enum YAML_STRING = "...";
instead of const YAML_STRING = "...";
it works fine.
P.S. It still strikes me as a bit odd though...

From dlang:
Enum declarations are used to define a group of constants.
or, from Çehreli tutorial:
enum is the feature that enables defining named constant values.
instead const is a "type qualifier", and indicates a variables that cannot be modified.

Related

ANTLR4 - How to change source code and get it back?

I'd like to rewrite some of the code.
Then, I'd like to get the rewritten code back.
First, I'd like to replace string literals:
local var = "%%var%%"
// to
local var = "SOMETHING"
Second, I'd like to erase the function name and brackets:
function sayHello (a)
local var = "%%var%%"
print("Hello")
end
//to
function (a)
local var = "%%var%%"
print("Hello")
end
What's the suggested way to do so?
My target's JavaScript (specifically antlr4ts), however an answer in any language is welcome.
Use TokenStreamRewriter
const stream = CharStreams.fromString(code);
const lexer = new LuaLexer(stream);
const commonTokenStream = new CommonTokenStream(lexer);
const rewriter = new TokenStreamRewriter(commonTokenStream);
const parser = new LuaParser(commonTokenStream);
const tree = parser.chunk();
class MyVisitor extends AbstractParseTreeVisitor<any>
implements LuaVisitor<any> {
constructor() {
super();
}
visitString(ctx: StringContext) {
rewriter.replace(ctx.start.tokenIndex, ctx.stop?.tokenIndex!, "SOME REPLACEMENT");
}
}
console.log("rewriter", rewriter.getText());

Typescript: Enforce a type to be "string literal" and not <string>

Problem
Is there a way in Typescript to define a type that is only a string literal, excluding string itself?
Note that I am not talking about a certain list of string literal; for which, a simple union of "Value1" | "Value2", or an enum type would work. I am talking about any string literal, but not string itself.
Example Code
type OnlyStringLiterals = ...; // <--- what should we put here?
const v1: OnlyStringLiterals = "hi"; // should work
const v2: OnlyStringLiterals = "bye"; // should work
// and so should be for any single string value assigned
// But:
const v3: OnlyStringLiterals = ("red" as string); // should NOT work -- it's string
Use Case
I am doing Branding on the types in my code, and I am passing a brand name, as a template, to my parent class. See the code below:
abstract class MyAbstractClass<
BRAND_T extends string,
VALUE_T = string
> {
constructor(private readonly _value: VALUE_T) { }
getValue(): VALUE_T { return this._value; }
private _Brand?: BRAND_T; // required to error on the last line, as intended!
}
class FirstName extends MyAbstractClass<"FirstName"> {
}
class AdminRole extends MyAbstractClass<"AdminRole"> {
}
class SubClassWithMissedName extends MyAbstractClass<string> {
// I want this to error! ........................ ^^^^^^
}
function printName(name: FirstName) {
console.log(name.getValue());
}
const userFirstName = new FirstName("Alex");
const userRole = new AdminRole("Moderator");
printName(userRole); // Already errors, as expected
Playground Link
I want to make sure every subclass is passing exactly a string literal, and not just string to the parent class.
I found an answer that works for my use case, but is not the most reusable one. Just sharing it anyway.
Thought Process
I believe it's not possible to have one solid type to represent what I wanted, because I cannot even think what will show up in VS Code if I hover over it!
However, to my knowledge, there is a function-style checking in Typescript for types that you can pass a type in and expect a type back, and finally assign a value to it to see if it goes through.
Type-checking using a Generic Type and a follow-up assignment
Using this technique I am thinking about the following template type:
type TrueStringLiterals<T extends string> = string extends T ? never : true;
const v1 = "hi";
const check1: TrueStringLiterals<typeof v1> = true; // No error :-)
const v2 = "bye";
const check2: TrueStringLiterals<typeof v2> = true; // No error :-)
const v3 = ("red" as string);
const check3: TrueStringLiterals<typeof v3> = true; // Errors, as expected!
Playground Link
Easier in an already-passed Generic Type
Also, in my use case, I am doing:
abstract class MyAbstractClass<
BRAND_T extends (string extends BRAND_T ? never : string),
VALUE_T = string
> {
...
Playground Link
... which works like a charm!
You can create utility type which will allow only on subset of string:
type SubString<T> = T extends string ?
string extends T ? never
: T
: never
const makeSubStr = <T extends string>(a: SubString<T>) => a
const a = makeSubStr('strLiteral')
const b = makeSubStr('strLiteral' as string) // error
const c: string = 'elo I am string'
const d = makeSubStr(c) // error
const e: SubString<"red"> = ("red" as string); // error
This type will also return never if something is not a string, in your answer TrueStringLiterals will not take this case into consideration and pass it through.
The other answers don't catch the case where the provided type parameter is a union of literal strings. If this shall be explicitly avoided, as could be read from the OPs question, the following solution, based on the other two can be used:
type UnUnion<T, S> = T extends S ? ([S] extends [T] ? T : never) : never;
type NotUnion<T> = UnUnion<T, T>;
type LiteralString<T extends string> = string extends T ? never : NotUnion<T>;
where UnUnion uses the fact that if T is a union, say 'a' | 'b', the union is distributed over the rest of the type expression.
(['a'|'b'] extends ['a'] ? ... ) | (['a'|'b'] extends ['b'] ? ...)
If T is a union, none of these can hold and all the parts turn into never.
NotUnion reduces this to have just one generic parameter and LiteralString just uses its result in case its parameter is not extendable by string.
Playground Link
I'd like to submit an answer from a similar question I recently asked, that is far more simple than the examples given so far:
type SpecificString<S extends Exclude<string, S>> = S
let test1: SpecificString<"a" | "b" | "c"> // okay
let test2: SpecificString<string> // error
//guaranteed to work where `Exclude<string, T>` wouldn't
let test3: Exclude<SpecificString<"a" | "1">, "1">
test3 = "a" // okay
test3 = "1" // error
Basically how this works:
Exclude<string, "any string literal"> ==> resolves to string
Exclude<string, string> ==> resolves to never
You can call this F-bounded quantification if you like I guess.

How to use parseInt in kotlin?

I making fun increase, decrease for item count. I want make count.text plus "T" Character. when I tried to make code like this.
error code: java.lang.NumberFormatException: For input string: "1T"
How can I solve this problem? Any one can help??
fun increaseInteger() {
var count = findViewById<TextView>(R.id.integer_number)
count.text=intent.getStringExtra("case")+"T"
var countResult = parseInt(intent.getStringExtra("case")+"T")
var countValue = countResult+1
if (countValue >= 1 && !decrease.isEnabled) { decrease.isEnabled = true}
intent.putExtra("result",countValue)
display(countValue)
}
fun decreaseInteger() {
var count = findViewById<TextView>(R.id.integer_number)
count.text=intent.getStringExtra("case")+"T"
var countResult = parseInt(intent.getStringExtra("case")+"T")
var countValue = countResult-1
if (countValue <= 1) {decrease.isEnabled = false }
intent.putExtra("result",countValue)
display(countValue)
}
The API is pretty straightforward:
"123".toInt() // returns 123 as Int
"123T".toInt() // throws NumberFormatException
"123".toIntOrNull() // returns 123 Int?
"123T".toIntOrNull() // returns null as Int?
So if you know your input might not be parseable to an Int, you can use toIntOrNull which will return null if the value was not parseable. It allows to use further nullability tools the language offers, e.g.:
input.toIntOrNull() ?: throw IllegalArgumentException("$input is not a valid number")
(This example uses the elvis operator to handle the undesired null response of toIntOrNull, the alternative would involve a try/catch around toInt)
You can use these
val str = "12345"
val str_new = "12345B"
str.toInt() // returns 123 as Int
str_new.toInt() // throws NumberFormatException
str.toIntOrNull() // returns 123 Int?
str_new.toIntOrNull() // returns null as Int?

Turn a string literal type to a literal value

In TypeScript, we can have string literal types that allow us to do things like:
type HelloString = "Hello";
This lets me define something like a string enum as follows:
namespace Literals {
export type One = "one";
export type Two = "two";
}
And then I can define a union:
type Literal = Literals.One | Literals.Two;
Is there a way to extract the unique value of Literals.One as the type Literals.One?
The reason for this, is that when I define a function like this:
function doSomething(literal : Literal) {
}
I'd really love to do the following:
doSomething(Literals.One);
But I can't. I have to write:
doSomething("one");
You can have types and values with the same name inside a namespace, so you can define constants for those values:
namespace Literals {
export type One = "one";
export type Two = "two";
export const One: One = "one";
export const Two: Two = "two";
}
const s: Literals.One = Literals.One;
console.log(s);
There is a probosal on github for string enums, they suggest the current best solution is the example above.
Turning a string literal type to a literal value is possible with custom transformers (https://github.com/Microsoft/TypeScript/pull/13940), which is available in typescript#next.
Please look into my npm package, ts-transformer-enumerate.
Example usage:
// The signature of `enumerate` here is `function enumerate<T extends string>(): { [K in T]: K };`
import { enumerate } from 'ts-transformer-enumerate';
type Colors = 'green' | 'yellow' | 'red';
const Colors = enumerate<Colors>();
console.log(Colors.green); // 'green'
console.log(Colors.yellow); // 'yellow'
console.log(Colors.red); // 'red'

Haxe Int to String

It seems AS3 has a toString() for the Number class. Is there an equivalent in Haxe? The only solution I could come up with for converting an Int to a String is a function like:
public function IntToString(i:Int):String {
var strbuf:StringBuf = new StringBuf();
strbuf.add(i);
return strbuf.toString();
}
Is there a better method that I'm overlooking?
You don't usually need to manually convert an int to a string because the conversion is automatic.
var i = 1;
var s = "" + i; // s is now "1"
The "formal" way to convert any value to a string is to use Std.string():
var s = Std.string(i);
You could also use string interpolation:
var s = '$i';
The function your wrote is fine but definitely overkilling.

Resources