#how do you all get around not being able to switch on strings?
1 messages · Page 1 of 1 (latest)
For simple stuff where performance is not critical, e.g. checking the values of command line flags at program start:
if (std.mem.eql(u8, arg, "--verbose")) ...
Otherwise you can use a std.HashMap when the set of keys is dynamically determined, or a std.ComptimeStringMap when the set of keys is fixed and known at comptime.
Try Out InK's Patented Solution™️:
const str: []const u8 = ....;
const Case = enum {
fizz,
buzz,
@"fizz buzz",
};
const case = std.meta.stringToEnum(Case, str) orelse {
// handle non-matching case
};
switch (case) {
.fizz => {},
.buzz => {},
.@"fizz buzz" => {},
}
for enums with less than 100 members or something, it uses std.ComptimeStringMap under the hood
I would like to purchase a license to your solution, I'll have my people call your people
We'll get back to you in 1.25 business days
lol thanks yall
@shy rock how are you getting syntax highlighting? I thought there was no zig support
there isn't. I just arbitrarily add a language tag that looks good for the particular code lol
that one's typescript (ts)
It's not in the language ref, but I call them "quoted identifiers"
Or "escaped identifiers"
how do you read about how they work?
essentially, they can contain any valid unicode text, minus something like the null character
can also use unicode codepoint literals in them, e.g. @"\u{77}"
certainly makes for some funky stuff
also allows you to use keywords as identifiers
@"return"
which, generally is the main use case for them
@shy rock you got a version of that enum solution for std.mem.startsWith?
nay, not quite. That would be quite a bit more complex I imagine
I don't think that would be possible, switch checks for integer equality essentially
Yeah 😭
you also can't do a for loop over const character data?
fn parser(input: [*:0]const u8) TOKEN {
std.debug.print("THE INPUT{s}", .{input});
var tokens: []Token = undefined;
comptime var cur_tok_start = 0;
comptime var token_depth = 0;
for (input) |char| {
_ = char;
const case = std.meta.stringToEnum(Case, input[cur_tok_start..(cur_tok_start + 1)]);
// token = token ++ char;
switch (case) {
.function => {
tokens = tokens ++ Token {
.kind = TOKEN.FUNCTION,
.value = "function"
};
cur_tok_start += token_depth;
token_depth = 0;
},
else => {
token_depth += 1;
}
}
}
return tokens;
}```
not if it doesn't have a length
[*:0]const u8 is a plain pointer, which has no length encoded into the type, nor does it carry attached any runtime length information like a slice would
it just happens to be annotated as having a 0 sentinel
we could get it's length
we're comptime
pub fn main() !void {
comptime {
const javascript = @embedFile("./test.js");
const tokens = parser(javascript);
std.debug.print("THE TOKENS {}", .{tokens});
}
}```
if you want, you could transform this into a slice using a function like std.mem.sliceTo or std.mem.span.
Also, no, this isn't being done at comptime, not in the function
there is a distinction between a function which can be called at comptime, and a function which is comptime-only
if you wanted that to be comptime, the parameter would have to be comptime input: [*:0]const u8
I'd prefer for this function to be comptime only
why?
I'm looking at targeting zig from js
if you make it comptime-only, input can never be from any external data
right
there's an input js file
and i want to generate zig that does the same thing as the js
so we have everything
I would still recommend against making it comptime-only unless you actually need to
at any rate, to get back to the main question
just make your parameter be input: []const u8, or input: [:0]const u8
Oh, I do notice now that it can only be comptime only
few other fixes:
surround the whole function body in a comptime block instead of having comptime vars, and declare tokens as:
var tokens: []const Token = &.{};
src/main.zig:44:13: error: switch on type '?main.Case'
switch (case) {
^~~~
like I demonstrated in my original example, that function returns ?Case, you have to unwrap it first
To help you understand this error in the future, switch only works on ints or things that are ints under the hood: errors, enums, tagged unions (tags are ints). But not optionals, although there is a proposal for that.
gotcha
looks like there are still some comptime issues
src/main.zig:46:18: error: unable to resolve comptime value
tokens = tokens ++ Token {
^~~~~~
nvm
well...
switch (case) {
.function => {
comptime var newTok = [_]Token{Token {
.kind = TOKEN.FUNCTION,
.val = "function"
}};
tokens = tokens ++ newTok;
cur_tok_start += token_depth;
token_depth = 0;
},
else => {
token_depth += 1;
}
}
}
seems hard to not make my Token a const pointer if I want to define it literally
src/main.zig:51:25: error: expected type '[]main.Token', found '*const [1]main.Token'
tokens = tokens ++ newTok;
~~~~~~~^~~~~~~~~
tried this which doesn't work
comptime var newTok: [*]Token = undefined;
newTok[0] = Token {
.kind = TOKEN.FUNCTION,
.val = "function"
};
src/main.zig:51:15: error: use of undefined value here causes undefined behavior
newTok[0] = Token {
~~~~~~^~~
Problem there is that var newTok: [*]Token = undefined creates an uninitialized pointer, not a pointer to an uninitialized array
like I said earlier
wrap all of your code in a comptime block
and also fix your uninitialised pointer
undefined is not the same as empty
if you want an empty slice or w/e, you need to at least assign &.{}
I would shorten your line to
tokens = tokens ++ &[_]Token{.{
.kind = TOKEN.FUNCTION,
.val = "function",
}};
Comptime code into creating an enum with all possible starts from the current enum names
seems to still be upset even with the comptime block and fixed initialization
fn parser(comptime input: [:0]const u8) []Token {
comptime {
var tokens: []Token = &.{};
var cur_tok_start = 0;
var token_depth = 0;
for (input) |char| {
_ = char;
var case = std.meta.stringToEnum(Case, input[cur_tok_start..(cur_tok_start + token_depth)]) orelse Case.ident;
// std.debug.print("THE CASE {}", .{case});
// @compileLog(cur_tok_start, cur_tok_s)
// @compileLog("THE CASE {}", input[cur_tok_start..(cur_tok_start + 1)]);
switch (case) {
.function => {
tokens = tokens ++ &[_]Token{ .{
.kind = TOKEN.FUNCTION,
.val = "function"
}};
cur_tok_start += token_depth;
token_depth = 0;
},
else => {
token_depth += 1;
}
}
}
return tokens;
}
}```
src/main.zig:49:25: error: expected type '[]main.Token', found '*const [1]main.Token'
tokens = tokens ++ &[_]Token{ .{
~~~~~~~^~
needs to be []const Token
there's not really a good and safe way to return mutable comptime memory
hence your recommendation against doing as much in comptime as I was indicating I'd like I guess...
though, later if you want to be able to modify the list of tokens for whatever reason, you can just do something like:
var tokens = parser(input)[0..].*;
to make it an array
well I'm eventually going to be turning thsi into a while loop
and continually adding to tokens
ah no sorry the for loop is achieving it... i lapsed for a sec
right now the compiler is still upset even with the const
what's the error
/Users/interpretations/projects/zigscript$ zig build-exe src/main.zig -freference-trace
src/main.zig:50:33: error: pointer modifier 'const' not allowed on array child type
tokens = tokens ++ [_]const Token{ .{
^~~~~
that's only for the slice
arrays are value types, and can't have attributes related to memory
that should remain as &[_]Token{.{ ... }}
ah I see I think
well now I'm going through my loop too many times... so I'm going to work on fixing that, and hopefully we'll see that this works once I get past that error
I think I'm going to try going through this soon https://www.youtube.com/watch?v=VgjRyaRTH6E
seems to have a lot of details about the things that tend to trip me up
haven't actually seen that
it appears that for some reason...
@compileLog("\n", input[cur_tok_start..(cur_tok_start + token_depth)], "\n");
is just giving me the entire input
even if I know that those values that are used to get a slice of the input are say 1, and 0
I'll ask that you open a new post for that