Compare commits

...

1 Commits

Author SHA1 Message Date
Jarred Sumner
280c7b0831 Shrink the CSS parser 2024-11-14 03:56:58 -08:00
18 changed files with 485 additions and 383 deletions

View File

@@ -126,7 +126,7 @@ pub const PrintErr = error{
pub fn OOM(e: anyerror) noreturn {
if (comptime bun.Environment.isDebug) {
std.debug.assert(e == std.mem.Allocator.Error.OutOfMemory);
assert(e == std.mem.Allocator.Error.OutOfMemory);
}
bun.outOfMemory();
}
@@ -246,6 +246,14 @@ pub fn todo(comptime fmt: []const u8, args: anytype) noreturn {
std.debug.panic("TODO: " ++ fmt, args);
}
fn RuntimeVoidWrap(comptime T: type) type {
return struct {
fn wrapped(fn_ptr: *const fn (*Parser) Result(T), p: *Parser) Result(T) {
return fn_ptr(p);
}
};
}
pub fn voidWrap(comptime T: type, comptime parsefn: *const fn (*Parser) Result(T)) *const fn (void, *Parser) Result(T) {
const Wrapper = struct {
fn wrapped(_: void, p: *Parser) Result(T) {
@@ -954,12 +962,12 @@ fn parse_at_rule(
name: []const u8,
parser: *P,
pub fn parsefn(this: *@This(), input2: *Parser) Result(P.AtRuleParser.Prelude) {
pub fn parsefn(this: *const @This(), input2: *Parser) Result(P.AtRuleParser.Prelude) {
return P.AtRuleParser.parsePrelude(this.parser, this.name, input2);
}
};
var closure = Closure{ .name = name, .parser = parser };
const prelude: P.AtRuleParser.Prelude = switch (input.parseUntilBefore(delimiters, P.AtRuleParser.Prelude, &closure, Closure.parsefn)) {
const closure = Closure{ .name = name, .parser = parser };
const prelude: P.AtRuleParser.Prelude = switch (input.parseUntilBefore(delimiters, P.AtRuleParser.Prelude, *const Closure, &closure, Closure.parsefn)) {
.result => |vvv| vvv,
.err => |e| {
// const end_position = input.position();
@@ -1004,16 +1012,16 @@ fn parse_at_rule(
prelude: P.AtRuleParser.Prelude,
start: *const ParserState,
parser: *P,
pub fn parsefn(this: *@This(), input2: *Parser) Result(P.AtRuleParser.AtRule) {
pub fn parsefn(this: *const @This(), input2: *Parser) Result(P.AtRuleParser.AtRule) {
return P.AtRuleParser.parseBlock(this.parser, this.prelude, this.start, input2);
}
};
var another_closure = AnotherClosure{
const another_closure = AnotherClosure{
.prelude = prelude,
.start = start,
.parser = parser,
};
return parse_nested_block(input, P.AtRuleParser.AtRule, &another_closure, AnotherClosure.parsefn);
return parse_nested_block(input, P.AtRuleParser.AtRule, *const AnotherClosure, &another_closure, AnotherClosure.parsefn);
},
else => {
bun.unreachablePanic("", .{});
@@ -1099,7 +1107,7 @@ fn parse_qualified_rule(
) Result(P.QualifiedRuleParser.QualifiedRule) {
ValidQualifiedRuleParser(P);
const prelude_result = brk: {
const prelude = input.parseUntilBefore(delimiters, P.QualifiedRuleParser.Prelude, parser, P.QualifiedRuleParser.parsePrelude);
const prelude = input.parseUntilBefore(delimiters, P.QualifiedRuleParser.Prelude, *P, parser, P.QualifiedRuleParser.parsePrelude);
break :brk prelude;
};
if (input.expectCurlyBracketBlock().asErr()) |e| return .{ .err = e };
@@ -1112,16 +1120,16 @@ fn parse_qualified_rule(
prelude: P.QualifiedRuleParser.Prelude,
parser: *P,
pub fn parsefn(this: *@This(), input2: *Parser) Result(P.QualifiedRuleParser.QualifiedRule) {
pub fn parsefn(this: *const @This(), input2: *Parser) Result(P.QualifiedRuleParser.QualifiedRule) {
return P.QualifiedRuleParser.parseBlock(this.parser, this.prelude, this.start, input2);
}
};
var closure = Closure{
const closure = Closure{
.start = start,
.prelude = prelude,
.parser = parser,
};
return parse_nested_block(input, P.QualifiedRuleParser.QualifiedRule, &closure, Closure.parsefn);
return parse_nested_block(input, P.QualifiedRuleParser.QualifiedRule, *const Closure, &closure, Closure.parsefn);
}
fn parse_until_before(
@@ -1129,8 +1137,9 @@ fn parse_until_before(
delimiters_: Delimiters,
error_behavior: ParseUntilErrorBehavior,
comptime T: type,
closure: anytype,
comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T),
comptime Closure: type,
closure: Closure,
parse_fn: *const fn (Closure, *Parser) Result(T),
) Result(T) {
const delimiters = parser.stop_before.bitwiseOr(delimiters_);
const result = result: {
@@ -1143,7 +1152,7 @@ fn parse_until_before(
.stop_before = delimiters,
.import_records = parser.import_records,
};
const result = delimited_parser.parseEntirely(T, closure, parse_fn);
const result = delimited_parser.parseEntirely(T, Closure, closure, parse_fn);
if (error_behavior == .stop and result.isErr()) {
return result;
}
@@ -1172,15 +1181,16 @@ fn parse_until_before(
// fn parse_until_before_impl(parser: *Parser, delimiters: Delimiters, error_behavior: Parse
pub fn parse_until_after(
fn parse_until_after(
parser: *Parser,
delimiters: Delimiters,
error_behavior: ParseUntilErrorBehavior,
comptime T: type,
closure: anytype,
comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T),
comptime Closure: type,
closure: Closure,
parsefn: *const fn (Closure, *Parser) Result(T),
) Result(T) {
const result = parse_until_before(parser, delimiters, error_behavior, T, closure, parsefn);
const result = parse_until_before(parser, delimiters, error_behavior, T, Closure, closure, parsefn);
const is_err = result.isErr();
if (error_behavior == .stop and is_err) {
return result;
@@ -1197,7 +1207,7 @@ pub fn parse_until_after(
return result;
}
fn parse_nested_block(parser: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
fn parse_nested_block(parser: *Parser, comptime T: type, comptime Closure: type, closure: Closure, comptime parsefn: *const fn (Closure, *Parser) Result(T)) Result(T) {
const block_type: BlockType = if (parser.at_start_of) |block_type| brk: {
parser.at_start_of = null;
break :brk block_type;
@@ -1218,7 +1228,7 @@ fn parse_nested_block(parser: *Parser, comptime T: type, closure: anytype, compt
.stop_before = closing_delimiter,
.import_records = parser.import_records,
};
const result = nested_parser.parseEntirely(T, closure, parsefn);
const result = nested_parser.parseEntirely(T, Closure, closure, parsefn);
if (nested_parser.at_start_of) |block_type2| {
consume_until_end_of_block(block_type2, &nested_parser.input.tokenizer);
}
@@ -2618,7 +2628,7 @@ pub fn StyleSheetParser(comptime P: type) type {
.semicolon = true,
.close_curly_bracket = true,
};
_ = this.input.parseUntilAfter(delimiters, void, {}, voidWrap(void, Parser.parseEmpty));
_ = this.input.parseUntilAfter(delimiters, void, void, {}, voidWrap(void, Parser.parseEmpty));
} else {
return parse_at_rule(allocator, &start, name, this.input, P, this.parser);
}
@@ -3141,16 +3151,16 @@ pub fn RuleBodyParser(comptime P: type) type {
const Closure = struct {
parser: *P,
name: []const u8,
pub fn parsefn(self: *@This(), input: *Parser) Result(I) {
pub fn parsefn(self: *const @This(), input: *Parser) Result(I) {
if (input.expectColon().asErr()) |e| return .{ .err = e };
return P.DeclarationParser.parseValue(self.parser, self.name, input);
}
};
var closure = Closure{
const closure = Closure{
.parser = this.parser,
.name = name,
};
break :result parse_until_after(this.input, Delimiters{ .semicolon = true }, error_behavior, I, &closure, Closure.parsefn);
break :result parse_until_after(this.input, Delimiters{ .semicolon = true }, error_behavior, I, *const Closure, &closure, Closure.parsefn);
};
if (result.isErr() and parse_qualified) {
this.input.reset(&start);
@@ -3182,7 +3192,7 @@ pub fn RuleBodyParser(comptime P: type) type {
const token = tok.*;
const Closure = struct { token: Token, start: ParserState };
break :result this.input.parseUntilAfter(Delimiters{ .semicolon = true }, I, &Closure{ .token = token, .start = start }, struct {
break :result this.input.parseUntilAfter(Delimiters{ .semicolon = true }, I, *const Closure, &Closure{ .token = token, .start = start }, struct {
pub fn parseFn(closure: *const Closure, i: *Parser) Result(I) {
_ = i; // autofix
return .{ .err = closure.start.sourceLocation().newUnexpectedTokenError(closure.token) };
@@ -3355,7 +3365,7 @@ pub const Parser = struct {
}
/// Implementation of Vec::<T>::parse
pub fn parseList(this: *Parser, comptime T: type, comptime parse_one: *const fn (*Parser) Result(T)) Result(ArrayList(T)) {
pub fn parseList(this: *Parser, comptime T: type, parse_one: *const fn (*Parser) Result(T)) Result(ArrayList(T)) {
return this.parseCommaSeparated(T, parse_one);
}
@@ -3373,25 +3383,29 @@ pub const Parser = struct {
pub fn parseCommaSeparated(
this: *Parser,
comptime T: type,
comptime parse_one: *const fn (*Parser) Result(T),
parse_one: *const fn (*Parser) Result(T),
) Result(ArrayList(T)) {
return this.parseCommaSeparatedInternal(T, {}, voidWrap(T, parse_one), false);
const Wrapper = RuntimeVoidWrap(T);
const parse_fn = &Wrapper.wrapped;
return this.parseCommaSeparatedInternal(T, @TypeOf(parse_one), parse_one, parse_fn, false);
}
pub fn parseCommaSeparatedWithCtx(
this: *Parser,
comptime T: type,
closure: anytype,
comptime parse_one: *const fn (@TypeOf(closure), *Parser) Result(T),
comptime Ctx: type,
closure: Ctx,
parse_one: *const fn (Ctx, *Parser) Result(T),
) Result(ArrayList(T)) {
return this.parseCommaSeparatedInternal(T, closure, parse_one, false);
return this.parseCommaSeparatedInternal(T, Ctx, closure, parse_one, false);
}
fn parseCommaSeparatedInternal(
this: *Parser,
comptime T: type,
closure: anytype,
comptime parse_one: *const fn (@TypeOf(closure), *Parser) Result(T),
comptime Closure: type,
closure: Closure,
parse_one: *const fn (Closure, *Parser) Result(T),
ignore_errors: bool,
) Result(ArrayList(T)) {
// Vec grows from 0 to 4 by default on first push(). So allocate with
@@ -3408,7 +3422,7 @@ pub const Parser = struct {
while (true) {
this.skipWhitespace(); // Unnecessary for correctness, but may help try() in parse_one rewind less.
switch (this.parseUntilBefore(Delimiters{ .comma = true }, T, closure, parse_one)) {
switch (this.parseUntilBefore(Delimiters{ .comma = true }, T, Closure, closure, parse_one)) {
.result => |v| {
values.append(alloc, v) catch unreachable;
},
@@ -3458,7 +3472,7 @@ pub const Parser = struct {
return result;
}
pub inline fn tryParseImpl(this: *Parser, comptime Ret: type, comptime func: anytype, args: anytype) Ret {
pub fn tryParseImpl(this: *Parser, comptime Ret: type, comptime func: anytype, args: anytype) Ret {
const start = this.state();
const result = result: {
break :result @call(.auto, func, args);
@@ -3470,7 +3484,11 @@ pub const Parser = struct {
}
pub inline fn parseNestedBlock(this: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
return parse_nested_block(this, T, closure, parsefn);
return parseNestedBlockT(this, T, @TypeOf(closure), closure, parsefn);
}
pub inline fn parseNestedBlockT(this: *Parser, comptime T: type, comptime Closure: type, closure: Closure, comptime parsefn: *const fn (Closure, *Parser) Result(T)) Result(T) {
return parse_nested_block(this, T, Closure, closure, parsefn);
}
pub fn isExhausted(this: *Parser) bool {
@@ -3731,12 +3749,12 @@ pub const Parser = struct {
return .{ .err = start_location.newUnexpectedTokenError(tok.*) };
}
pub fn position(this: *Parser) usize {
pub fn position(this: *const Parser) usize {
bun.debugAssert(bun.strings.isOnCharBoundary(this.input.tokenizer.src, this.input.tokenizer.position));
return this.input.tokenizer.position;
}
fn parseEmpty(_: *Parser) Result(void) {
fn parseEmpty(_: *const Parser) Result(void) {
return .{ .result = {} };
}
@@ -3749,24 +3767,26 @@ pub const Parser = struct {
this: *Parser,
delimiters: Delimiters,
comptime T: type,
closure: anytype,
comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T),
comptime Closure: type,
closure: Closure,
parse_fn: *const fn (Closure, *Parser) Result(T),
) Result(T) {
return parse_until_after(
this,
delimiters,
ParseUntilErrorBehavior.consume,
T,
Closure,
closure,
parse_fn,
);
}
pub fn parseUntilBefore(this: *Parser, delimiters: Delimiters, comptime T: type, closure: anytype, comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
return parse_until_before(this, delimiters, .consume, T, closure, parse_fn);
pub fn parseUntilBefore(this: *Parser, delimiters: Delimiters, comptime T: type, comptime Closure: type, closure: Closure, parse_fn: *const fn (Closure, *Parser) Result(T)) Result(T) {
return parse_until_before(this, delimiters, .consume, T, Closure, closure, parse_fn);
}
pub fn parseEntirely(this: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) {
pub inline fn parseEntirely(this: *Parser, comptime T: type, comptime Closure: type, closure: Closure, parsefn: *const fn (Closure, *Parser) Result(T)) Result(T) {
const result = switch (parsefn(closure, this)) {
.err => |e| return .{ .err = e },
.result => |v| v,
@@ -3840,7 +3860,7 @@ pub const Parser = struct {
if (this.import_records) |import_records| import_records.len = state_.import_record_count;
}
pub fn state(this: *Parser) ParserState {
pub fn state(this: *const Parser) ParserState {
return ParserState{
.position = this.input.tokenizer.getPosition(),
.current_line_start_position = this.input.tokenizer.current_line_start_position,
@@ -4249,18 +4269,18 @@ const Tokenizer = struct {
};
}
pub fn prev(this: *Tokenizer) Token {
pub fn prev(this: *const Tokenizer) Token {
bun.assert(this.position > 0);
return this.previous;
}
pub inline fn isEof(this: *Tokenizer) bool {
pub inline fn isEof(this: *const Tokenizer) bool {
return this.position >= this.src.len;
}
pub fn seeFunction(this: *Tokenizer, name: []const u8) void {
if (this.var_or_env_functions == .looking_for_them) {
if (std.ascii.eqlIgnoreCase(name, "var") and std.ascii.eqlIgnoreCase(name, "env")) {
if (name.len == 3 and bun.strings.eqlCaseInsensitiveASCII(name, "var", false) or bun.strings.eqlCaseInsensitiveASCII(name, "env", false)) {
this.var_or_env_functions = .seen_at_least_one;
}
}
@@ -5174,7 +5194,7 @@ const Tokenizer = struct {
pub fn consumeNewline(this: *Tokenizer) void {
const byte = this.nextByteUnchecked();
if (bun.Environment.allow_assert) {
std.debug.assert(byte == '\r' or byte == '\n' or byte == FORM_FEED_BYTE);
assert(byte == '\r' or byte == '\n' or byte == FORM_FEED_BYTE);
}
this.position += 1;
if (byte == '\r' and this.nextByte() == '\n') {
@@ -5194,7 +5214,7 @@ const Tokenizer = struct {
/// 11110xxx 0xF0..0xF7 First byte of a 4-byte character encoding
/// 10xxxxxx 0x80..0xBF Continuation byte: one of 1-3 bytes following the first <--
pub fn consumeContinuationByte(this: *Tokenizer) void {
if (bun.Environment.allow_assert) std.debug.assert(this.nextByteUnchecked() & 0xC0 == 0x80);
if (bun.Environment.allow_assert) assert(this.nextByteUnchecked() & 0xC0 == 0x80);
// Continuation bytes contribute to column overcount. Note
// that due to the special case for the 4-byte sequence intro,
// we must use wrapping add here.
@@ -5212,7 +5232,7 @@ const Tokenizer = struct {
/// 11110xxx 0xF0..0xF7 First byte of a 4-byte character encoding <--
/// 10xxxxxx 0x80..0xBF Continuation byte: one of 1-3 bytes following the first
pub fn consume4byteIntro(this: *Tokenizer) void {
if (bun.Environment.allow_assert) std.debug.assert(this.nextByteUnchecked() & 0xF0 == 0xF0);
if (bun.Environment.allow_assert) assert(this.nextByteUnchecked() & 0xF0 == 0xF0);
// This takes two UTF-16 characters to represent, so we
// actually have an undercount.
// this.current_line_start_position = self.current_line_start_position.wrapping_sub(1);
@@ -5220,7 +5240,7 @@ const Tokenizer = struct {
this.position += 1;
}
pub fn isIdentStart(this: *Tokenizer) bool {
pub fn isIdentStart(this: *const Tokenizer) bool {
// todo_stuff.match_byte
return !this.isEof() and switch (this.nextByteUnchecked()) {
@@ -5239,19 +5259,19 @@ const Tokenizer = struct {
/// If true, the input has at least `n` bytes left *after* the current one.
/// That is, `tokenizer.char_at(n)` will not panic.
fn hasAtLeast(this: *Tokenizer, n: usize) bool {
fn hasAtLeast(this: *const Tokenizer, n: usize) bool {
return this.position + n < this.src.len;
}
fn hasNewlineAt(this: *Tokenizer, offset: usize) bool {
fn hasNewlineAt(this: *const Tokenizer, offset: usize) bool {
return this.position + offset < this.src.len and switch (this.byteAt(offset)) {
'\n', '\r', FORM_FEED_BYTE => true,
else => false,
};
}
pub fn startsWith(this: *Tokenizer, comptime needle: []const u8) bool {
return std.mem.eql(u8, this.src[this.position .. this.position + needle.len], needle);
pub fn startsWith(this: *const Tokenizer, comptime needle: []const u8) bool {
return bun.strings.hasPrefixComptime(this.src[this.position..], needle);
}
/// Advance over N bytes in the input. This function can advance
@@ -5264,8 +5284,8 @@ const Tokenizer = struct {
// rejected.
for (0..n) |i| {
const b = this.byteAt(i);
std.debug.assert(std.ascii.isASCII(b) or (b & 0xF0 != 0xF0 and b & 0xC0 != 0x80));
std.debug.assert(b != '\r' and b != '\n' and b != '\x0C');
assert(std.ascii.isASCII(b) or (b & 0xF0 != 0xF0 and b & 0xC0 != 0x80));
assert(b != '\r' and b != '\n' and b != '\x0C');
}
}
this.position += n;
@@ -5273,7 +5293,7 @@ const Tokenizer = struct {
/// Advance over any kind of byte, excluding newlines.
pub fn consumeKnownByte(this: *Tokenizer, byte: u8) void {
if (bun.Environment.allow_assert) std.debug.assert(byte != '\r' and byte != '\n' and byte != FORM_FEED_BYTE);
if (bun.Environment.allow_assert) assert(byte != '\r' and byte != '\n' and byte != FORM_FEED_BYTE);
this.position += 1;
// Continuation bytes contribute to column overcount.
if (byte & 0xF0 == 0xF0) {
@@ -5287,25 +5307,25 @@ const Tokenizer = struct {
}
}
pub inline fn byteAt(this: *Tokenizer, n: usize) u8 {
pub inline fn byteAt(this: *const Tokenizer, n: usize) u8 {
return this.src[this.position + n];
}
pub inline fn nextByte(this: *Tokenizer) ?u8 {
pub inline fn nextByte(this: *const Tokenizer) ?u8 {
if (this.isEof()) return null;
return this.src[this.position];
}
pub inline fn nextChar(this: *Tokenizer) u32 {
pub inline fn nextChar(this: *const Tokenizer) u32 {
const len = bun.strings.utf8ByteSequenceLength(this.src[this.position]);
return bun.strings.decodeWTF8RuneT(this.src[this.position..].ptr[0..4], len, u32, bun.strings.unicode_replacement);
}
pub inline fn nextByteUnchecked(this: *Tokenizer) u8 {
pub inline fn nextByteUnchecked(this: *const Tokenizer) u8 {
return this.src[this.position];
}
pub inline fn sliceFrom(this: *Tokenizer, start: usize) []const u8 {
pub inline fn sliceFrom(this: *const Tokenizer, start: usize) []const u8 {
return this.src[start..this.position];
}
};
@@ -6828,3 +6848,5 @@ fn restrict_prec(buf: []u8, comptime prec: u8) struct { []u8, Notation } {
pub inline fn fract(val: f32) f32 {
return val - @trunc(val);
}
const assert = bun.assert;

View File

@@ -153,7 +153,7 @@ pub const DeclarationBlock = struct {
context: *css.PropertyHandlerContext,
) void {
const handle = struct {
inline fn handle(
fn handle(
self: *This,
ctx: *css.PropertyHandlerContext,
hndlr: *DeclarationHandler,
@@ -299,12 +299,12 @@ pub fn parse_declaration(
property_id: css.PropertyId,
options: *const css.ParserOptions,
};
var closure = Closure{
const closure = Closure{
.property_id = property_id,
.options = options,
};
const property = switch (input.parseUntilBefore(delimiters, css.Property, &closure, struct {
pub fn parseFn(this: *Closure, input2: *css.Parser) Result(css.Property) {
const property = switch (input.parseUntilBefore(delimiters, css.Property, *const Closure, &closure, struct {
pub fn parseFn(this: *const Closure, input2: *css.Parser) Result(css.Property) {
return css.Property.parse(this.property_id, input2, this.options);
}
}.parseFn)) {

View File

@@ -156,7 +156,7 @@ pub fn canTransitivelyImplementEql(comptime T: type) bool {
};
}
pub inline fn eql(comptime T: type, lhs: *const T, rhs: *const T) bool {
pub fn eql(comptime T: type, lhs: *const T, rhs: *const T) bool {
const tyinfo = comptime @typeInfo(T);
if (comptime tyinfo == .Pointer) {
if (comptime T == []const u8) return bun.strings.eql(lhs.*, rhs.*);
@@ -264,7 +264,7 @@ pub inline fn deepClone(comptime T: type, this: *const T, allocator: Allocator)
}
const Angle = css_values.angle.Angle;
pub inline fn tryFromAngle(comptime T: type, angle: Angle) ?T {
pub fn tryFromAngle(comptime T: type, angle: Angle) ?T {
return switch (T) {
CSSNumber => CSSNumberFns.tryFromAngle(angle),
Angle => return Angle.tryFromAngle(angle),
@@ -285,7 +285,7 @@ pub inline fn trySign(comptime T: type, val: *const T) ?f32 {
pub inline fn tryMap(
comptime T: type,
val: *const T,
comptime map_fn: *const fn (a: f32) f32,
map_fn: *const fn (a: f32) f32,
) ?T {
return switch (T) {
CSSNumber => map_fn(val.*),
@@ -301,31 +301,33 @@ pub inline fn tryOpTo(
comptime R: type,
lhs: *const T,
rhs: *const T,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) R,
) ?R {
return switch (T) {
CSSNumber => op_fn(ctx, lhs.*, rhs.*),
else => {
if (@hasDecl(T, "opTo")) return T.opTo(lhs, rhs, R, ctx, op_fn);
return T.tryOpTo(lhs, rhs, R, ctx, op_fn);
if (@hasDecl(T, "opTo")) return T.opTo(lhs, rhs, R, Ctx, ctx, op_fn);
return T.tryOpTo(lhs, rhs, R, Ctx, ctx, op_fn);
},
};
}
pub inline fn tryOp(
pub fn tryOp(
comptime T: type,
lhs: *const T,
rhs: *const T,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) f32,
) ?T {
return switch (T) {
Angle => Angle.tryOp(lhs, rhs, ctx, op_fn),
Angle => Angle.tryOp(lhs, rhs, Ctx, ctx, op_fn),
CSSNumber => op_fn(ctx, lhs.*, rhs.*),
else => {
if (@hasDecl(T, "op")) return T.op(lhs, rhs, ctx, op_fn);
return T.tryOp(lhs, rhs, ctx, op_fn);
if (@hasDecl(T, "op")) return T.op(lhs, rhs, Ctx, ctx, op_fn);
return T.tryOp(lhs, rhs, Ctx, ctx, op_fn);
},
};
}

View File

@@ -49,7 +49,7 @@ pub const MediaList = struct {
pub fn parse(input: *css.Parser) Result(MediaList) {
var media_queries = ArrayList(MediaQuery){};
while (true) {
const mq = switch (input.parseUntilBefore(css.Delimiters{ .comma = true }, MediaQuery, {}, css.voidWrap(MediaQuery, MediaQuery.parse))) {
const mq = switch (input.parseUntilBefore(css.Delimiters{ .comma = true }, MediaQuery, void, {}, css.voidWrap(MediaQuery, MediaQuery.parse))) {
.result => |v| v,
.err => |e| {
if (e.kind == .basic and e.kind.basic == .end_of_input) break;

View File

@@ -198,7 +198,7 @@ pub fn Printer(comptime Writer: type) type {
};
}
pub inline fn getImportRecords(this: *This) PrintErr!*const bun.BabyList(bun.ImportRecord) {
pub fn getImportRecords(this: *This) PrintErr!*const bun.BabyList(bun.ImportRecord) {
if (this.import_records) |import_records| return import_records;
try this.addNoImportRecordError();
unreachable;
@@ -215,13 +215,13 @@ pub fn Printer(comptime Writer: type) type {
return this.addNoImportRecordError();
}
pub inline fn importRecord(this: *Printer(Writer), import_record_idx: u32) PrintErr!*const bun.ImportRecord {
pub fn importRecord(this: *Printer(Writer), import_record_idx: u32) PrintErr!*const bun.ImportRecord {
if (this.import_records) |import_records| return import_records.at(import_record_idx);
try this.addNoImportRecordError();
unreachable;
}
pub inline fn getImportRecordUrl(this: *This, import_record_idx: u32) PrintErr![]const u8 {
pub fn getImportRecordUrl(this: *This, import_record_idx: u32) PrintErr![]const u8 {
return (try this.importRecord(import_record_idx)).path.text;
}

View File

@@ -925,7 +925,7 @@ pub const UnresolvedColor = union(enum) {
const Closure = struct {
options: *const css.ParserOptions,
parser: *ComponentParser,
pub fn parsefn(this: *@This(), input2: *css.Parser) Result(UnresolvedColor) {
pub fn parsefn(this: *const @This(), input2: *css.Parser) Result(UnresolvedColor) {
return this.parser.parseRelative(input2, HSL, UnresolvedColor, @This().innerParseFn, .{this.options});
}
pub fn innerParseFn(i: *css.Parser, p: *ComponentParser, opts: *const css.ParserOptions) Result(UnresolvedColor) {
@@ -951,7 +951,7 @@ pub const UnresolvedColor = union(enum) {
} };
}
};
var closure = Closure{
const closure = Closure{
.options = options,
.parser = &parser,
};
@@ -960,8 +960,8 @@ pub const UnresolvedColor = union(enum) {
const Closure = struct {
options: *const css.ParserOptions,
parser: *ComponentParser,
pub fn parsefn(this: *@This(), input2: *css.Parser) Result(UnresolvedColor) {
const light = switch (input2.parseUntilBefore(css.Delimiters{ .comma = true }, TokenList, this, @This().parsefn2)) {
pub fn parsefn(this: *const @This(), input2: *css.Parser) Result(UnresolvedColor) {
const light = switch (input2.parseUntilBefore(css.Delimiters{ .comma = true }, TokenList, *const css.ParserOptions, this.options, @This().parsefn2)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -982,11 +982,11 @@ pub const UnresolvedColor = union(enum) {
} };
}
pub fn parsefn2(this: *@This(), input2: *css.Parser) Result(TokenList) {
return TokenListFns.parse(input2, this.options, 1);
pub fn parsefn2(parser_options: *const css.ParserOptions, input2: *css.Parser) Result(TokenList) {
return TokenListFns.parse(input2, parser_options, 1);
}
};
var closure = Closure{
const closure = Closure{
.options = options,
.parser = &parser,
};
@@ -1412,10 +1412,9 @@ pub const UnparsedProperty = struct {
value: TokenList,
pub fn parse(property_id: css.PropertyId, input: *css.Parser, options: *const css.ParserOptions) Result(UnparsedProperty) {
const Closure = struct { options: *const css.ParserOptions };
const value = switch (input.parseUntilBefore(css.Delimiters{ .bang = true, .semicolon = true }, css.TokenList, &Closure{ .options = options }, struct {
pub fn parseFn(self: *const Closure, i: *css.Parser) Result(TokenList) {
return TokenList.parse(i, self.options, 0);
const value = switch (input.parseUntilBefore(css.Delimiters{ .bang = true, .semicolon = true }, css.TokenList, *const css.ParserOptions, options, struct {
pub fn parseFn(parser_options: *const css.ParserOptions, i: *css.Parser) Result(TokenList) {
return TokenList.parse(i, parser_options, 0);
}
}.parseFn)) {
.result => |v| v,
@@ -1444,24 +1443,19 @@ pub const CustomProperty = struct {
pub fn parse(name: CustomPropertyName, input: *css.Parser, options: *const css.ParserOptions) Result(CustomProperty) {
const Closure = struct {
options: *const css.ParserOptions,
pub fn parsefn(this: *@This(), input2: *css.Parser) Result(TokenList) {
return TokenListFns.parse(input2, this.options, 0);
pub fn parsefn(parser_options: *const css.ParserOptions, input2: *css.Parser) Result(TokenList) {
return TokenListFns.parse(input2, parser_options, 0);
}
};
var closure = Closure{
.options = options,
};
const value = switch (input.parseUntilBefore(
css.Delimiters{
.bang = true,
.semicolon = true,
},
TokenList,
&closure,
*const css.ParserOptions,
options,
Closure.parsefn,
)) {
.result => |v| v,

View File

@@ -241,7 +241,7 @@ pub fn StyleRule(comptime R: type) type {
/// Returns whether this rule is a duplicate of another rule.
/// This means it has the same selectors and properties.
pub inline fn isDuplicate(this: *const This, other: *const This) bool {
pub fn isDuplicate(this: *const This, other: *const This) bool {
return this.declarations.len() == other.declarations.len() and
this.selectors.eql(&other.selectors) and
brk: {

View File

@@ -1550,7 +1550,7 @@ pub fn GenericSelectorList(comptime Impl: type) type {
.nesting_requirement = nesting_requirement,
.parser = parser,
};
const selector = input.parseUntilBefore(css.Delimiters{ .comma = true }, SelectorT, &closure, Closure.parsefn);
const selector = input.parseUntilBefore(css.Delimiters{ .comma = true }, SelectorT, *Closure, &closure, Closure.parsefn);
const was_ok = selector.isOk();
switch (selector) {
@@ -1610,7 +1610,7 @@ pub fn GenericSelectorList(comptime Impl: type) type {
.nesting_requirement = nesting_requirement,
.parser = parser,
};
const selector = input.parseUntilBefore(css.Delimiters{ .comma = true }, SelectorT, &closure, Closure.parsefn);
const selector = input.parseUntilBefore(css.Delimiters{ .comma = true }, SelectorT, *Closure, &closure, Closure.parsefn);
const was_ok = selector.isOk();
switch (selector) {

View File

@@ -866,7 +866,7 @@ pub const serialize = struct {
}
const Helpers = struct {
pub inline fn writePrefixed(
pub fn writePrefixed(
d: *Printer(W),
prefix: css.VendorPrefix,
comptime val: []const u8,
@@ -881,7 +881,7 @@ pub const serialize = struct {
try vp.toCss(W, d);
try d.writeStr(val);
}
pub inline fn pseudo(
pub fn pseudo(
d: *Printer(W),
comptime key: []const u8,
comptime s: []const u8,
@@ -1583,7 +1583,7 @@ const CompoundSelectorIter = struct {
/// .split(|x| x.is_combinator()) // splits the slice into subslices by elements that match over the predicate
/// .rev() // reverse
/// ```
pub inline fn next(this: *@This()) ?[]const parser.Component {
pub fn next(this: *@This()) ?[]const parser.Component {
// Since we iterating backwards, we convert all indices into "backwards form" by doing `this.sel.components.items.len - 1 - i`
while (this.i < this.sel.components.items.len) {
const next_index: ?usize = next_index: {

View File

@@ -53,7 +53,7 @@ pub fn SmallList(comptime T: type, comptime N: comptime_int) type {
var values: @This() = .{};
while (true) {
input.skipWhitespace();
switch (input.parseUntilBefore(Delimiters{ .comma = true }, T, {}, parseFn)) {
switch (input.parseUntilBefore(Delimiters{ .comma = true }, T, void, {}, parseFn)) {
.result => |v| {
values.append(input.allocator(), v);
},

View File

@@ -170,7 +170,7 @@ pub const Angle = union(Tag) {
};
}
pub fn map(this: *const Angle, comptime opfn: *const fn (f32) f32) Angle {
pub fn map(this: *const Angle, opfn: *const fn (f32) f32) Angle {
return switch (this.*) {
.deg => |deg| .{ .deg = opfn(deg) },
.rad => |rad| .{ .rad = opfn(rad) },
@@ -179,7 +179,7 @@ pub const Angle = union(Tag) {
};
}
pub fn tryMap(this: *const Angle, comptime opfn: *const fn (f32) f32) ?Angle {
pub fn tryMap(this: *const Angle, opfn: *const fn (f32) f32) ?Angle {
return map(this, opfn);
}
@@ -189,7 +189,7 @@ pub const Angle = union(Tag) {
return a + b;
}
};
return Angle.op(&this, &rhs, {}, addfn.add);
return Angle.op(&this, &rhs, void, {}, addfn.add);
}
pub fn tryAdd(this: *const Angle, _: std.mem.Allocator, rhs: *const Angle) ?Angle {
@@ -217,27 +217,30 @@ pub const Angle = union(Tag) {
pub fn tryOp(
this: *const Angle,
other: *const Angle,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) f32,
) ?Angle {
return Angle.op(this, other, ctx, op_fn);
return Angle.op(this, other, Ctx, ctx, op_fn);
}
pub fn tryOpTo(
this: *const Angle,
other: *const Angle,
comptime R: type,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) R,
) ?R {
return Angle.opTo(this, other, R, ctx, op_fn);
return Angle.opTo(this, other, R, Ctx, ctx, op_fn);
}
pub fn op(
this: *const Angle,
other: *const Angle,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) f32,
) Angle {
// PERF: not sure if this is faster
const self_tag: u8 = @intFromEnum(this.*);
@@ -261,8 +264,9 @@ pub const Angle = union(Tag) {
this: *const Angle,
other: *const Angle,
comptime T: type,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) T,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) T,
) T {
// PERF: not sure if this is faster
const self_tag: u8 = @intFromEnum(this.*);

View File

@@ -45,6 +45,32 @@ pub fn needsDeepclone(comptime V: type) bool {
};
}
const CalcUnit = enum {
abs,
acos,
asin,
atan,
atan2,
calc,
clamp,
cos,
exp,
hypot,
log,
max,
min,
mod,
pow,
rem,
round,
sign,
sin,
sqrt,
tan,
pub const Map = bun.ComptimeEnumMap(CalcUnit);
};
/// A mathematical expression used within the `calc()` function.
///
/// This type supports generic value types. Values such as `Length`, `Percentage`,
@@ -266,39 +292,14 @@ pub fn Calc(comptime V: type) type {
return null;
}
};
return parseWith(input, {}, Fn.parseWithFn);
return parseWith(input, void, {}, Fn.parseWithFn);
}
const CalcUnit = enum {
abs,
acos,
asin,
atan,
atan2,
calc,
clamp,
cos,
exp,
hypot,
log,
max,
min,
mod,
pow,
rem,
round,
sign,
sin,
sqrt,
tan,
pub const Map = bun.ComptimeEnumMap(CalcUnit);
};
pub fn parseWith(
input: *css.Parser,
ctx: anytype,
comptime parseIdent: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parseIdent: *const fn (Ctx, []const u8) ?This,
) Result(This) {
const location = input.currentSourceLocation();
const f = switch (input.expectFunction()) {
@@ -308,14 +309,22 @@ pub fn Calc(comptime V: type) type {
switch (CalcUnit.Map.getAnyCase(f) orelse return .{ .err = location.newUnexpectedTokenError(.{ .ident = f }) }) {
.calc => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
return This.parseSum(i, self.ctx, parseIdent);
pub fn parseNestedBlockFn(state: *const State, i: *css.Parser) Result(This) {
return This.parseSum(i, Ctx, state.ctx, state.parse_ident);
}
};
var closure = Closure{ .ctx = ctx };
const calc = switch (input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn)) {
const calc = switch (input.parseNestedBlockT(
This,
*const State,
&State{
.ctx = ctx,
.parse_ident = parseIdent,
},
Closure.parseNestedBlockFn,
)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -329,17 +338,20 @@ pub fn Calc(comptime V: type) type {
} };
},
.min => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(ArrayList(This)) {
return i.parseCommaSeparatedWithCtx(This, self, @This().parseOne);
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(ArrayList(This)) {
return i.parseCommaSeparatedWithCtx(This, *const State, self, @This().parseOne);
}
pub fn parseOne(self: *@This(), i: *css.Parser) Result(This) {
return This.parseSum(i, self.ctx, parseIdent);
pub fn parseOne(self: *const State, i: *css.Parser) Result(This) {
return This.parseSum(i, Ctx, self.ctx, self.parse_ident);
}
};
var closure = Closure{ .ctx = ctx };
var reduced = switch (input.parseNestedBlock(ArrayList(This), &closure, Closure.parseNestedBlockFn)) {
var reduced = switch (input.parseNestedBlockT(ArrayList(This), *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -360,17 +372,19 @@ pub fn Calc(comptime V: type) type {
} };
},
.max => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(ArrayList(This)) {
return i.parseCommaSeparatedWithCtx(This, self, @This().parseOne);
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(ArrayList(This)) {
return i.parseCommaSeparatedWithCtx(This, *const State, self, @This().parseOne);
}
pub fn parseOne(self: *@This(), i: *css.Parser) Result(This) {
return This.parseSum(i, self.ctx, parseIdent);
pub fn parseOne(self: *const State, i: *css.Parser) Result(This) {
return This.parseSum(i, Ctx, self.ctx, self.parse_ident);
}
};
var closure = Closure{ .ctx = ctx };
var reduced = switch (input.parseNestedBlock(ArrayList(This), &closure, Closure.parseNestedBlockFn)) {
var reduced = switch (input.parseNestedBlockT(ArrayList(This), *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -390,37 +404,33 @@ pub fn Calc(comptime V: type) type {
},
.clamp => {
const ClosureResult = struct { ?This, This, ?This };
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlock(self: *@This(), i: *css.Parser) Result(ClosureResult) {
const min = switch (This.parseSum(i, self, parseIdentWrapper)) {
pub fn parseNestedBlock(self: *const State, i: *css.Parser) Result(ClosureResult) {
const min = switch (This.parseSum(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
if (i.expectComma().asErr()) |e| return .{ .err = e };
const center = switch (This.parseSum(i, self, parseIdentWrapper)) {
const center = switch (This.parseSum(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
if (i.expectComma().asErr()) |e| return .{ .err = e };
const max = switch (This.parseSum(i, self, parseIdentWrapper)) {
const max = switch (This.parseSum(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
return .{ .result = .{ min, center, max } };
}
pub fn parseIdentWrapper(self: *@This(), ident: []const u8) ?This {
return parseIdent(self.ctx, ident);
}
};
var closure = Closure{
.ctx = ctx,
};
var min, var center, var max = switch (input.parseNestedBlock(
var min, var center, var max = switch (input.parseNestedBlockT(
ClosureResult,
&closure,
*const State,
&State{
.ctx = ctx,
.parse_ident = parseIdent,
},
Closure.parseNestedBlock,
)) {
.result => |vv| vv,
@@ -492,9 +502,9 @@ pub fn Calc(comptime V: type) type {
} };
},
.round => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
const strategy = if (i.tryParse(RoundingStrategy.parse, .{}).asValue()) |s| brk: {
if (i.expectComma().asErr()) |e| return .{ .err = e };
break :brk s;
@@ -503,11 +513,11 @@ pub fn Calc(comptime V: type) type {
const OpAndFallbackCtx = struct {
strategy: RoundingStrategy,
pub fn op(this: *const @This(), a: f32, b: f32) f32 {
pub fn op(this: @This(), a: f32, b: f32) f32 {
return round({}, a, b, this.strategy);
}
pub fn fallback(this: *const @This(), a: This, b: This) MathFunction(V) {
pub fn fallback(this: @This(), a: This, b: This) MathFunction(V) {
return MathFunction(V){
.round = .{
.strategy = this.strategy,
@@ -517,36 +527,40 @@ pub fn Calc(comptime V: type) type {
};
}
};
var ctx_for_op_and_fallback = OpAndFallbackCtx{
const ctx_for_op_and_fallback = OpAndFallbackCtx{
.strategy = strategy,
};
return This.parseMathFn(
i,
&ctx_for_op_and_fallback,
OpAndFallbackCtx,
ctx_for_op_and_fallback,
OpAndFallbackCtx.op,
OpAndFallbackCtx.fallback,
Ctx,
self.ctx,
parseIdent,
self.parse_ident,
);
}
};
var closure = Closure{
return input.parseNestedBlockT(This, *const State, &.{
.ctx = ctx,
};
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.rem => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
return This.parseMathFn(
i,
void,
{},
@This().rem,
mathFunctionRem,
Ctx,
self.ctx,
parseIdent,
self.parse_ident,
);
}
@@ -562,23 +576,25 @@ pub fn Calc(comptime V: type) type {
};
}
};
var closure = Closure{
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
};
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.mod => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
return This.parseMathFn(
i,
void,
{},
@This().modulo,
mathFunctionMod,
Ctx,
self.ctx,
parseIdent,
self.parse_ident,
);
}
@@ -595,34 +611,35 @@ pub fn Calc(comptime V: type) type {
};
}
};
var closure = Closure{
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
};
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.sin => {
return This.parseTrig(input, .sin, false, ctx, parseIdent);
return This.parseTrig(input, .sin, false, Ctx, ctx, parseIdent);
},
.cos => {
return This.parseTrig(input, .cos, false, ctx, parseIdent);
return This.parseTrig(input, .cos, false, Ctx, ctx, parseIdent);
},
.tan => {
return This.parseTrig(input, .tan, false, ctx, parseIdent);
return This.parseTrig(input, .tan, false, Ctx, ctx, parseIdent);
},
.asin => {
return This.parseTrig(input, .asin, true, ctx, parseIdent);
return This.parseTrig(input, .asin, true, Ctx, ctx, parseIdent);
},
.acos => {
return This.parseTrig(input, .acos, true, ctx, parseIdent);
return This.parseTrig(input, .acos, true, Ctx, ctx, parseIdent);
},
.atan => {
return This.parseTrig(input, .atan, true, ctx, parseIdent);
return This.parseTrig(input, .atan, true, Ctx, ctx, parseIdent);
},
.atan2 => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
const res = switch (This.parseAtan2(i, self.ctx, parseIdent)) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
const res = switch (This.parseAtan2(i, Ctx, self.ctx, self.parse_ident)) {
.result => |v| v,
.err => |e| return .{ .err = e },
};
@@ -639,21 +656,23 @@ pub fn Calc(comptime V: type) type {
return .{ .err = i.newCustomError(css.ParserError{ .invalid_value = {} }) };
}
};
var closure = Closure{ .ctx = ctx };
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.pow => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
const a = switch (This.parseNumeric(i, self.ctx, parseIdent)) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
const a = switch (This.parseNumeric(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
if (i.expectComma().asErr()) |e| return .{ .err = e };
const b = switch (This.parseNumeric(i, self.ctx, parseIdent)) {
const b = switch (This.parseNumeric(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -663,19 +682,21 @@ pub fn Calc(comptime V: type) type {
} };
}
};
var closure = Closure{ .ctx = ctx };
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.log => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
const value = switch (This.parseNumeric(i, self.ctx, parseIdent)) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
const value = switch (This.parseNumeric(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
if (i.tryParse(css.Parser.expectComma, .{}).isOk()) {
const base = switch (This.parseNumeric(i, self.ctx, parseIdent)) {
const base = switch (This.parseNumeric(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -684,20 +705,22 @@ pub fn Calc(comptime V: type) type {
return .{ .result = This{ .number = std.math.log(f32, std.math.e, value) } };
}
};
var closure = Closure{ .ctx = ctx };
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.sqrt => {
return This.parseNumericFn(input, .sqrt, ctx, parseIdent);
return This.parseNumericFn(input, .sqrt, Ctx, ctx, parseIdent);
},
.exp => {
return This.parseNumericFn(input, .exp, ctx, parseIdent);
return This.parseNumericFn(input, .exp, Ctx, ctx, parseIdent);
},
.hypot => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
var args = switch (i.parseCommaSeparatedWithCtx(This, self, parseOne)) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
var args = switch (i.parseCommaSeparatedWithCtx(This, *const State, self, parseOne)) {
.result => |v| v,
.err => |e| return .{ .err = e },
};
@@ -717,18 +740,20 @@ pub fn Calc(comptime V: type) type {
} };
}
pub fn parseOne(self: *@This(), i: *css.Parser) Result(This) {
return This.parseSum(i, self.ctx, parseIdent);
pub fn parseOne(self: *const State, i: *css.Parser) Result(This) {
return This.parseSum(i, Ctx, self.ctx, self.parse_ident);
}
};
var closure = Closure{ .ctx = ctx };
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.abs => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
const v = switch (This.parseSum(i, self.ctx, parseIdent)) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
const v = switch (This.parseSum(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -743,14 +768,16 @@ pub fn Calc(comptime V: type) type {
};
}
};
var closure = Closure{ .ctx = ctx };
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
.sign => {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
const v = switch (This.parseSum(i, self.ctx, parseIdent)) {
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
const v = switch (This.parseSum(i, Ctx, self.ctx, self.parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -786,25 +813,36 @@ pub fn Calc(comptime V: type) type {
} };
}
};
var closure = Closure{ .ctx = ctx };
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
return input.parseNestedBlockT(This, *const State, &State{
.ctx = ctx,
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
},
}
}
pub fn parseNumericFn(input: *css.Parser, comptime op: enum { sqrt, exp }, ctx: anytype, comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This) Result(This) {
const Closure = struct { ctx: @TypeOf(ctx) };
var closure = Closure{ .ctx = ctx };
const NumericFnOp = enum { sqrt, exp };
pub fn parseNumericFn(input: *css.Parser, op: NumericFnOp, comptime Ctx: type, ctx: Ctx, parse_ident: *const fn (Ctx, []const u8) ?This) Result(This) {
const Closure = struct {
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
op: NumericFnOp,
};
const closure = Closure{
.ctx = ctx,
.parse_ident = parse_ident,
.op = op,
};
return input.parseNestedBlock(This, &closure, struct {
pub fn parseNestedBlockFn(self: *Closure, i: *css.Parser) Result(This) {
const v = switch (This.parseNumeric(i, self.ctx, parse_ident)) {
pub fn parseNestedBlockFn(self: *const Closure, i: *css.Parser) Result(This) {
const v = switch (This.parseNumeric(i, Ctx, self.ctx, self.parse_ident)) {
.result => |v| v,
.err => |e| return .{ .err = e },
};
return .{
.result = Calc(V){
.number = switch (op) {
.number = switch (self.op) {
.sqrt => std.math.sqrt(v),
.exp => std.math.exp(v),
},
@@ -816,23 +854,25 @@ pub fn Calc(comptime V: type) type {
pub fn parseMathFn(
input: *css.Parser,
ctx_for_op_and_fallback: anytype,
comptime op: *const fn (@TypeOf(ctx_for_op_and_fallback), f32, f32) f32,
comptime fallback: *const fn (@TypeOf(ctx_for_op_and_fallback), This, This) MathFunction(V),
ctx_for_parse_ident: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx_for_parse_ident), []const u8) ?This,
comptime CtxForOpAndFallback: type,
ctx_for_op_and_fallback: CtxForOpAndFallback,
op: *const fn (CtxForOpAndFallback, f32, f32) f32,
fallback: *const fn (CtxForOpAndFallback, This, This) MathFunction(V),
comptime CtxForParseIdent: type,
ctx_for_parse_ident: CtxForParseIdent,
parse_ident: *const fn (CtxForParseIdent, []const u8) ?This,
) Result(This) {
const a = switch (This.parseSum(input, ctx_for_parse_ident, parse_ident)) {
const a = switch (This.parseSum(input, CtxForParseIdent, ctx_for_parse_ident, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
if (input.expectComma().asErr()) |e| return .{ .err = e };
const b = switch (This.parseSum(input, ctx_for_parse_ident, parse_ident)) {
const b = switch (This.parseSum(input, CtxForParseIdent, ctx_for_parse_ident, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
const val = This.applyOp(&a, &b, input.allocator(), ctx_for_op_and_fallback, op) orelse This{
const val = This.applyOp(&a, &b, input.allocator(), CtxForOpAndFallback, ctx_for_op_and_fallback, op) orelse This{
.function = bun.create(
input.allocator(),
MathFunction(V),
@@ -843,12 +883,13 @@ pub fn Calc(comptime V: type) type {
return .{ .result = val };
}
pub fn parseSum(
fn parseSum(
input: *css.Parser,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
) Result(This) {
var cur = switch (This.parseProduct(input, ctx, parse_ident)) {
var cur = switch (This.parseProduct(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -871,13 +912,13 @@ pub fn Calc(comptime V: type) type {
.err => |e| return .{ .err = e },
};
if (next_tok.* == .delim and next_tok.delim == '+') {
const next = switch (Calc(V).parseProduct(input, ctx, parse_ident)) {
const next = switch (Calc(V).parseProduct(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
cur = cur.add(input.allocator(), next);
} else if (next_tok.* == .delim and next_tok.delim == '-') {
var rhs = switch (This.parseProduct(input, ctx, parse_ident)) {
var rhs = switch (This.parseProduct(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -897,8 +938,9 @@ pub fn Calc(comptime V: type) type {
pub fn parseProduct(
input: *css.Parser,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
) Result(This) {
var node = switch (This.parseValue(input, ctx, parse_ident)) {
.result => |vv| vv,
@@ -916,7 +958,7 @@ pub fn Calc(comptime V: type) type {
if (tok.* == .delim and tok.delim == '*') {
// At least one of the operands must be a number.
const rhs = switch (This.parseValue(input, ctx, parse_ident)) {
const rhs = switch (This.parseValueT(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -930,7 +972,7 @@ pub fn Calc(comptime V: type) type {
return .{ .err = input.newUnexpectedTokenError(.{ .delim = '*' }) };
}
} else if (tok.* == .delim and tok.delim == '/') {
const rhs = switch (This.parseValue(input, ctx, parse_ident)) {
const rhs = switch (This.parseValueT(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -951,11 +993,20 @@ pub fn Calc(comptime V: type) type {
pub fn parseValue(
input: *css.Parser,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
) Result(This) {
return parseValueT(input, @TypeOf(ctx), ctx, parse_ident);
}
fn parseValueT(
input: *css.Parser,
comptime Ctx: type,
ctx: Ctx,
parseIdent: *const fn (Ctx, []const u8) ?This,
) Result(This) {
// Parse nested calc() and other math functions.
if (input.tryParse(This.parse, .{}).asValue()) |_calc| {
const calc: This = _calc;
if (input.tryParse(This.parse, .{}).asValue()) |calc| {
switch (calc) {
.function => |f| return switch (f.*) {
.calc => |c| .{ .result = c },
@@ -966,16 +1017,16 @@ pub fn Calc(comptime V: type) type {
}
if (input.tryParse(css.Parser.expectParenthesisBlock, .{}).isOk()) {
const State = ClosureState(Ctx, This);
const Closure = struct {
ctx: @TypeOf(ctx),
pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) {
return This.parseSum(i, self.ctx, parse_ident);
pub fn parseNestedBlockFn(self: *const State, i: *css.Parser) Result(This) {
return This.parseSum(i, Ctx, self.ctx, self.parse_ident);
}
};
var closure = Closure{
return input.parseNestedBlock(This, &State{
.ctx = ctx,
};
return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn);
.parse_ident = parseIdent,
}, Closure.parseNestedBlockFn);
}
if (input.tryParse(css.Parser.expectNumber, .{}).asValue()) |num| {
@@ -988,7 +1039,7 @@ pub fn Calc(comptime V: type) type {
const location = input.currentSourceLocation();
if (input.tryParse(css.Parser.expectIdent, .{}).asValue()) |ident| {
if (parse_ident(ctx, ident)) |c| {
if (parseIdent(ctx, ident)) |c| {
return .{ .result = c };
}
@@ -1008,40 +1059,42 @@ pub fn Calc(comptime V: type) type {
} };
}
const TrigFn = enum {
sin,
cos,
tan,
asin,
acos,
atan,
pub fn run(this: @This(), x: f32) f32 {
return switch (this) {
.sin => std.math.sin(x),
.cos => std.math.cos(x),
.tan => std.math.tan(x),
.asin => std.math.asin(x),
.acos => std.math.acos(x),
.atan => std.math.atan(x),
};
}
};
pub fn parseTrig(
input: *css.Parser,
comptime trig_fn_kind: enum {
sin,
cos,
tan,
asin,
acos,
atan,
},
trig_fn: TrigFn,
to_angle: bool,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
) Result(This) {
const trig_fn = struct {
pub fn run(x: f32) f32 {
const mathfn = comptime switch (trig_fn_kind) {
.sin => std.math.sin,
.cos => std.math.cos,
.tan => std.math.tan,
.asin => std.math.asin,
.acos => std.math.acos,
.atan => std.math.atan,
};
return mathfn(x);
}
};
const Closure = struct {
ctx: @TypeOf(ctx),
ctx: Ctx,
to_angle: bool,
pub fn parseNestedBockFn(this: *@This(), i: *css.Parser) Result(This) {
trig_fn: TrigFn,
parse_ident: *const fn (Ctx, []const u8) ?This,
pub fn parseNestedBockFn(this: *const @This(), i: *css.Parser) Result(This) {
const v = switch (Calc(Angle).parseSum(
i,
*const @This(),
this,
@This().parseIdentFn,
)) {
@@ -1052,9 +1105,9 @@ pub fn Calc(comptime V: type) type {
const rad = rad: {
switch (v) {
.value => |angle| {
if (!this.to_angle) break :rad trig_fn.run(angle.toRadians());
if (!this.to_angle) break :rad this.trig_fn.run(angle.toRadians());
},
.number => break :rad trig_fn.run(v.number),
.number => break :rad this.trig_fn.run(v.number),
else => {},
}
return .{ .err = i.newCustomError(css.ParserError{ .invalid_value = {} }) };
@@ -1076,15 +1129,17 @@ pub fn Calc(comptime V: type) type {
}
}
pub fn parseIdentFn(this: *@This(), ident: []const u8) ?Calc(Angle) {
const v = parse_ident(this.ctx, ident) orelse return null;
pub fn parseIdentFn(this: *const @This(), ident: []const u8) ?Calc(Angle) {
const v = this.parse_ident(this.ctx, ident) orelse return null;
if (v == .number) return .{ .number = v.number };
return null;
}
};
var closure = Closure{
const closure = Closure{
.ctx = ctx,
.to_angle = to_angle,
.trig_fn = trig_fn,
.parse_ident = parse_ident,
};
return input.parseNestedBlock(This, &closure, Closure.parseNestedBockFn);
}
@@ -1099,10 +1154,10 @@ pub fn Calc(comptime V: type) type {
pub fn parseAtan2(
input: *css.Parser,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
) Result(Angle) {
const Ctx = @TypeOf(ctx);
// atan2 supports arguments of any <number>, <dimension>, or <percentage>, even ones that wouldn't
// normally be supported by V. The only requirement is that the arguments be of the same type.
@@ -1124,18 +1179,20 @@ pub fn Calc(comptime V: type) type {
}
const Closure = struct {
ctx: @TypeOf(ctx),
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
pub fn parseIdentFn(self: *@This(), ident: []const u8) ?Calc(CSSNumber) {
const v = parse_ident(self.ctx, ident) orelse return null;
pub fn parseIdentFn(self: *const @This(), ident: []const u8) ?Calc(CSSNumber) {
const v = self.parse_ident(self.ctx, ident) orelse return null;
if (v == .number) return .{ .number = v.number };
return null;
}
};
var closure = Closure{
const closure = Closure{
.ctx = ctx,
.parse_ident = parse_ident,
};
return Calc(CSSNumber).parseAtan2Args(input, &closure, Closure.parseIdentFn);
return Calc(CSSNumber).parseAtan2Args(input, *const Closure, &closure, Closure.parseIdentFn);
}
inline fn tryParseAtan2Args(
@@ -1145,20 +1202,21 @@ pub fn Calc(comptime V: type) type {
ctx: Ctx,
) Result(Angle) {
const func = ParseIdentNone(Ctx, Value).func;
return input.tryParseImpl(Result(Angle), Calc(Value).parseAtan2Args, .{ input, ctx, func });
return input.tryParseImpl(Result(Angle), Calc(Value).parseAtan2Args, .{ input, Ctx, ctx, func });
}
pub fn parseAtan2Args(
input: *css.Parser,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
) Result(Angle) {
const a = switch (This.parseSum(input, ctx, parse_ident)) {
const a = switch (This.parseSum(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
if (input.expectComma().asErr()) |e| return .{ .err = e };
const b = switch (This.parseSum(input, ctx, parse_ident)) {
const b = switch (This.parseSum(input, Ctx, ctx, parse_ident)) {
.result => |vv| vv,
.err => |e| return .{ .err = e },
};
@@ -1169,7 +1227,7 @@ pub fn Calc(comptime V: type) type {
return .{ .rad = std.math.atan2(x, y) };
}
};
if (css.generic.tryOpTo(V, Angle, a.value, b.value, {}, Fn.opToFn)) |v| {
if (css.generic.tryOpTo(V, Angle, a.value, b.value, void, {}, Fn.opToFn)) |v| {
return .{ .result = v };
}
} else if (a == .number and b == .number) {
@@ -1185,22 +1243,25 @@ pub fn Calc(comptime V: type) type {
pub fn parseNumeric(
input: *css.Parser,
ctx: anytype,
comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This,
comptime Ctx: type,
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
) Result(f32) {
const Closure = struct {
ctx: @TypeOf(ctx),
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
pub fn parseIdentFn(self: *@This(), ident: []const u8) ?Calc(CSSNumber) {
const v = parse_ident(self.ctx, ident) orelse return null;
pub fn parseIdentFn(self: *const @This(), ident: []const u8) ?Calc(CSSNumber) {
const v = self.parse_ident(self.ctx, ident) orelse return null;
if (v == .number) return .{ .number = v.number };
return null;
}
};
var closure = Closure{
const closure = Closure{
.ctx = ctx,
.parse_ident = parse_ident,
};
const v: Calc(CSSNumber) = switch (Calc(CSSNumber).parseSum(input, &closure, Closure.parseIdentFn)) {
const v: Calc(CSSNumber) = switch (Calc(CSSNumber).parseSum(input, *const Closure, &closure, Closure.parseIdentFn)) {
.result => |v| v,
.err => |e| return .{ .err = e },
};
@@ -1220,7 +1281,7 @@ pub fn Calc(comptime V: type) type {
}
if (args.items.len == 2) {
return .{ .result = This.applyOp(&args.items[0], &args.items[1], allocator, {}, hypot) };
return .{ .result = This.applyOp(&args.items[0], &args.items[1], allocator, void, {}, hypot) };
}
var i: usize = 0;
@@ -1238,7 +1299,7 @@ pub fn Calc(comptime V: type) type {
return a + bun.powf(b, 2);
}
};
sum = This.applyOp(&sum, arg, allocator, {}, Fn.applyOpFn) orelse {
sum = This.applyOp(&sum, arg, allocator, void, {}, Fn.applyOpFn) orelse {
errored = true;
break;
};
@@ -1253,11 +1314,12 @@ pub fn Calc(comptime V: type) type {
a: *const This,
b: *const This,
allocator: std.mem.Allocator,
ctx: anytype,
comptime op: *const fn (@TypeOf(ctx), f32, f32) f32,
comptime Ctx: type,
ctx: Ctx,
op: *const fn (Ctx, f32, f32) f32,
) ?This {
if (a.* == .value and b.* == .value) {
if (css.generic.tryOp(V, a.value, b.value, ctx, op)) |v| {
if (css.generic.tryOp(V, a.value, b.value, Ctx, ctx, op)) |v| {
return This{
.value = bun.create(
allocator,
@@ -1278,7 +1340,7 @@ pub fn Calc(comptime V: type) type {
return null;
}
pub fn applyMap(this: *const This, allocator: Allocator, comptime op: *const fn (f32) f32) ?This {
pub fn applyMap(this: *const This, allocator: Allocator, op: *const fn (f32) f32) ?This {
switch (this.*) {
.number => |n| return This{ .number = op(n) },
.value => |v| {
@@ -1848,3 +1910,10 @@ pub const Constant = enum {
fn absf(a: f32) f32 {
return @abs(a);
}
fn ClosureState(comptime Ctx: type, comptime This: type) type {
return struct {
ctx: Ctx,
parse_ident: *const fn (Ctx, []const u8) ?This,
};
}

View File

@@ -2273,7 +2273,7 @@ const RelativeComponentParser = struct {
angle: Angle,
parser: *const RelativeComponentParser,
pub fn tryParseFn(i: *css.Parser, t: *@This()) Result(Angle) {
if (Calc(Angle).parseWith(i, t, @This().calcParseIdentFn).asValue()) |val| {
if (Calc(Angle).parseWith(i, *@This(), t, @This().calcParseIdentFn).asValue()) |val| {
if (val == .value) {
return .{ .result = val.value.* };
}
@@ -2323,7 +2323,7 @@ const RelativeComponentParser = struct {
percentage: Percentage = .{ .v = 0 },
pub fn parsefn(i: *css.Parser, self: *@This()) Result(Percentage) {
if (Calc(Percentage).parseWith(i, self, @This().calcparseident).asValue()) |calc_value| {
if (Calc(Percentage).parseWith(i, *@This(), self, @This().calcparseident).asValue()) |calc_value| {
if (calc_value == .value) return .{ .result = calc_value.value.* };
}
return .{ .err = i.newCustomError(css.ParserError.invalid_value) };
@@ -2369,7 +2369,7 @@ const RelativeComponentParser = struct {
var _closure = Closure{ .self = this };
if (input.tryParse(struct {
pub fn parseFn(i: *css.Parser, closure: *Closure) Result(Percentage) {
const calc_value = switch (Calc(Percentage).parseWith(i, closure, parseIdentFn)) {
const calc_value = switch (Calc(Percentage).parseWith(i, *Closure, closure, parseIdentFn)) {
.result => |v| v,
.err => return .{ .err = i.newCustomError(css.ParserError.invalid_value) },
};
@@ -2434,16 +2434,16 @@ const RelativeComponentParser = struct {
p: *const RelativeComponentParser,
allowed_types: ChannelType,
pub fn parseIdentFn(self: *@This(), ident: []const u8) ?Calc(f32) {
pub fn parseIdentFn(self: *const @This(), ident: []const u8) ?Calc(f32) {
const v = self.p.getIdent(ident, self.allowed_types) orelse return null;
return .{ .number = v };
}
};
var closure = Closure{
const closure = Closure{
.p = this,
.allowed_types = allowed_types,
};
if (Calc(f32).parseWith(input, &closure, Closure.parseIdentFn).asValue()) |calc_val| {
if (Calc(f32).parseWith(input, *const Closure, &closure, Closure.parseIdentFn).asValue()) |calc_val| {
// PERF: I don't like this redundant allocation
if (calc_val == .value) return .{ .result = calc_val.value.* };
if (calc_val == .number) return .{ .result = calc_val.number };

View File

@@ -538,7 +538,7 @@ pub const ConicGradient = struct {
pub fn parse(input: *css.Parser) Result(ConicGradient) {
const angle = input.tryParse(struct {
inline fn parse(i: *css.Parser) Result(Angle) {
fn parse(i: *css.Parser) Result(Angle) {
if (i.expectIdentMatching("from").asErr()) |e| return .{ .err = e };
// Spec allows unitless zero angles for gradients.
// https://w3c.github.io/csswg-drafts/css-images-4/#valdef-conic-gradient-angle
@@ -547,7 +547,7 @@ pub const ConicGradient = struct {
}.parse, .{}).unwrapOr(Angle{ .deg = 0.0 });
const position = input.tryParse(struct {
inline fn parse(i: *css.Parser) Result(Position) {
fn parse(i: *css.Parser) Result(Position) {
if (i.expectIdentMatching("at").asErr()) |e| return .{ .err = e };
return Position.parse(i);
}
@@ -1543,6 +1543,7 @@ pub fn parseItems(comptime D: type, input: *css.Parser) Result(ArrayList(Gradien
if (input.parseUntilBefore(
css.Delimiters{ .comma = true },
void,
Closure,
Closure{ .items = &items, .seen_stop = &seen_stop },
struct {
fn parse(closure: Closure, i: *css.Parser) Result(void) {

View File

@@ -373,7 +373,7 @@ pub const LengthValue = union(enum) {
unreachable;
}
pub fn map(this: *const @This(), comptime map_fn: *const fn (f32) f32) LengthValue {
pub fn map(this: *const @This(), map_fn: *const fn (f32) f32) LengthValue {
inline for (comptime bun.meta.EnumFields(@This())) |field| {
if (field.value == @intFromEnum(this.*)) {
return @unionInit(LengthValue, field.name, map_fn(@field(this, field.name)));
@@ -419,8 +419,9 @@ pub const LengthValue = union(enum) {
pub fn tryOp(
this: *const LengthValue,
other: *const LengthValue,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) f32,
) ?LengthValue {
if (@intFromEnum(this.*) == @intFromEnum(other.*)) {
inline for (bun.meta.EnumFields(LengthValue)) |field| {
@@ -445,8 +446,9 @@ pub const LengthValue = union(enum) {
this: *const LengthValue,
other: *const LengthValue,
comptime R: type,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) R,
) ?R {
if (@intFromEnum(this.*) == @intFromEnum(other.*)) {
inline for (bun.meta.EnumFields(LengthValue)) |field| {
@@ -751,7 +753,7 @@ pub const Length = union(enum) {
return null;
}
pub fn tryMap(this: *const Length, comptime map_fn: *const fn (f32) f32) ?Length {
pub fn tryMap(this: *const Length, map_fn: *const fn (f32) f32) ?Length {
return switch (this.*) {
.value => |v| .{ .value = v.map(map_fn) },
else => null,
@@ -761,11 +763,12 @@ pub const Length = union(enum) {
pub fn tryOp(
this: *const Length,
other: *const Length,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) f32,
) ?Length {
if (this.* == .value and other.* == .value) {
if (this.value.tryOp(&other.value, ctx, op_fn)) |val| return .{ .value = val };
if (this.value.tryOp(&other.value, Ctx, ctx, op_fn)) |val| return .{ .value = val };
return null;
}
return null;
@@ -775,11 +778,12 @@ pub const Length = union(enum) {
this: *const Length,
other: *const Length,
comptime R: type,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) R,
) ?R {
if (this.* == .value and other.* == .value) {
return this.value.tryOpTo(&other.value, R, ctx, op_fn);
return this.value.tryOpTo(&other.value, R, Ctx, ctx, op_fn);
}
return null;
}

View File

@@ -90,7 +90,7 @@ pub const Percentage = struct {
return null;
}
pub fn tryMap(_: *const Percentage, comptime _: *const fn (f32) f32) ?Percentage {
pub fn tryMap(_: *const Percentage, _: *const fn (f32) f32) ?Percentage {
// Percentages cannot be mapped because we don't know what they will resolve to.
// For example, they might be positive or negative depending on what they are a
// percentage of, which we don't know.
@@ -100,8 +100,9 @@ pub const Percentage = struct {
pub fn op(
this: *const Percentage,
other: *const Percentage,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) f32,
) Percentage {
return Percentage{ .v = op_fn(ctx, this.v, other.v) };
}
@@ -110,8 +111,9 @@ pub const Percentage = struct {
this: *const Percentage,
other: *const Percentage,
comptime R: type,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) R,
) R {
return op_fn(ctx, this.v, other.v);
}
@@ -119,8 +121,9 @@ pub const Percentage = struct {
pub fn tryOp(
this: *const Percentage,
other: *const Percentage,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) f32,
) ?Percentage {
return Percentage{ .v = op_fn(ctx, this.v, other.v) };
}
@@ -430,7 +433,7 @@ pub fn DimensionPercentage(comptime D: type) type {
};
}
pub fn tryMap(this: *const This, comptime mapfn: *const fn (f32) f32) ?This {
pub fn tryMap(this: *const This, mapfn: *const fn (f32) f32) ?This {
return switch (this.*) {
.dimension => |vv| if (css.generic.tryMap(D, &vv, mapfn)) |v| .{ .dimension = v } else null,
else => null,
@@ -440,10 +443,11 @@ pub fn DimensionPercentage(comptime D: type) type {
pub fn tryOp(
this: *const This,
other: *const This,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, f32, f32) f32,
) ?This {
if (this.* == .dimension and other.* == .dimension) return .{ .dimension = css.generic.tryOp(D, &this.dimension, &other.dimension, ctx, op_fn) orelse return null };
if (this.* == .dimension and other.* == .dimension) return .{ .dimension = css.generic.tryOp(D, &this.dimension, &other.dimension, Ctx, ctx, op_fn) orelse return null };
if (this.* == .percentage and other.* == .percentage) return .{ .percentage = Percentage{ .v = op_fn(ctx, this.percentage.v, other.percentage.v) } };
return null;
}

View File

@@ -71,14 +71,14 @@ pub fn Size2D(comptime T: type) type {
return css.implementDeepClone(@This(), this, allocator);
}
pub inline fn valEql(lhs: *const T, rhs: *const T) bool {
pub fn valEql(lhs: *const T, rhs: *const T) bool {
return switch (T) {
f32 => lhs.* == rhs.*,
else => lhs.eql(rhs),
};
}
pub inline fn eql(lhs: *const @This(), rhs: *const @This()) bool {
pub fn eql(lhs: *const @This(), rhs: *const @This()) bool {
return switch (T) {
f32 => lhs.a == rhs.b,
else => lhs.a.eql(&rhs.b),

View File

@@ -149,7 +149,7 @@ pub const Time = union(enum) {
return css.generic.partialCmpF32(&this.toMs(), &other.toMs());
}
pub fn map(this: *const @This(), comptime map_fn: *const fn (f32) f32) Time {
pub fn map(this: *const @This(), map_fn: *const fn (f32) f32) Time {
return switch (this.*) {
.seconds => Time{ .seconds = map_fn(this.seconds) },
.milliseconds => Time{ .milliseconds = map_fn(this.milliseconds) },
@@ -166,8 +166,9 @@ pub const Time = union(enum) {
pub fn op(
this: *const Time,
other: *const Time,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) f32,
) Time {
const self_tag: u16 = @intFromEnum(this.*);
const other_tag: u16 = @intFromEnum(other.*);
@@ -188,8 +189,9 @@ pub const Time = union(enum) {
this: *const Time,
other: *const Time,
comptime R: type,
ctx: anytype,
comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R,
comptime Ctx: type,
ctx: Ctx,
op_fn: *const fn (Ctx, a: f32, b: f32) R,
) R {
const self_tag: u16 = @intFromEnum(this.*);
const other_tag: u16 = @intFromEnum(other.*);