Fix Kym error messages
This commit is contained in:
parent
07a515a81f
commit
071d890391
|
@ -25,18 +25,19 @@ pub fn Functor(comptime Output: type, comptime Input: type) type {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn bind(comptime State: type, state: *const State, comptime invoker: fn (capture: *const State, input: Input) Output) Self {
|
pub fn bind(comptime State: type, state: *const State, comptime invoker: fn (capture: *const State, input: Input) Output) Self {
|
||||||
|
const alignment = @alignOf(State);
|
||||||
|
const is_zero_aligned = alignment == 0;
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = state,
|
.context = if (is_zero_aligned) state else @ptrCast(*const anyopaque, state),
|
||||||
|
|
||||||
.invoker = struct {
|
.invoker = struct {
|
||||||
fn invoke_opaque(context: *const anyopaque, input: Input) Output {
|
fn invoke_opaque(context: *const anyopaque, input: Input) Output {
|
||||||
const state_alignment = @alignOf(State);
|
if (is_zero_aligned) {
|
||||||
|
|
||||||
if (state_alignment == 0) {
|
|
||||||
return invoker(@ptrCast(*const State, context), input);
|
return invoker(@ptrCast(*const State, context), input);
|
||||||
}
|
}
|
||||||
|
|
||||||
return invoker(@ptrCast(*const State, @alignCast(state_alignment, context)), input);
|
return invoker(@ptrCast(*const State, @alignCast(alignment, context)), input);
|
||||||
}
|
}
|
||||||
}.invoke_opaque,
|
}.invoke_opaque,
|
||||||
};
|
};
|
||||||
|
@ -60,18 +61,19 @@ pub fn Generator(comptime Output: type, comptime Input: type) type {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn bind(comptime State: type, state: *State, comptime invoker: fn (capture: *State, input: Input) Output) Self {
|
pub fn bind(comptime State: type, state: *State, comptime invoker: fn (capture: *State, input: Input) Output) Self {
|
||||||
|
const alignment = @alignOf(State);
|
||||||
|
const is_zero_aligned = alignment == 0;
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = state,
|
.context = if (is_zero_aligned) state else @ptrCast(*anyopaque, state),
|
||||||
|
|
||||||
.invoker = struct {
|
.invoker = struct {
|
||||||
fn invoke_opaque(context: *anyopaque, input: Input) Output {
|
fn invoke_opaque(context: *anyopaque, input: Input) Output {
|
||||||
const state_alignment = @alignOf(State);
|
if (is_zero_aligned) {
|
||||||
|
|
||||||
if (state_alignment == 0) {
|
|
||||||
return invoker(@ptrCast(*State, context), input);
|
return invoker(@ptrCast(*State, context), input);
|
||||||
}
|
}
|
||||||
|
|
||||||
return invoker(@ptrCast(*State, @alignCast(state_alignment, context)), input);
|
return invoker(@ptrCast(*State, @alignCast(alignment, context)), input);
|
||||||
}
|
}
|
||||||
}.invoke_opaque,
|
}.invoke_opaque,
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,26 +9,18 @@ const std = @import("std");
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub const ArgsContext = struct {
|
pub const DecimalFormat = struct {
|
||||||
writer: io.Writer,
|
delimiter: []const u8 = "",
|
||||||
index: usize,
|
positive_prefix: enum {none, plus, space} = .none,
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub const ArgsFormatter = io.Functor(PrintError!void, ArgsContext);
|
pub const HexadecimalFormat = struct {
|
||||||
|
|
||||||
///
|
|
||||||
/// Errors that may occur during utf8-encoded int parsing.
|
|
||||||
///
|
|
||||||
pub const IntParseError = math.CheckedArithmeticError || ParseError;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Optional rules for int parsing logic to consider during parsing.
|
|
||||||
///
|
|
||||||
pub const IntParseOptions = struct {
|
|
||||||
delimiter: []const u8 = "",
|
delimiter: []const u8 = "",
|
||||||
|
positive_prefix: enum {none, plus, space} = .none,
|
||||||
|
casing: enum {lower, upper} = .lower,
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -46,119 +38,105 @@ pub const PrintError = error {
|
||||||
PrintIncomplete,
|
PrintIncomplete,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn format_args(args: anytype) ArgsFormatter {
|
|
||||||
const Args = @TypeOf(args);
|
|
||||||
|
|
||||||
return ArgsFormatter.bind(Args, &args, struct {
|
|
||||||
fn get(typed_args: *const Args, context: ArgsContext) PrintError!void {
|
|
||||||
_ = typed_args;
|
|
||||||
_ = context;
|
|
||||||
}
|
|
||||||
}.get);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to parse a float value of type described by `float` from `utf8`.
|
|
||||||
///
|
///
|
||||||
/// The function returns a [ParseError] if `utf8` does not conform to the syntax of a float.
|
|
||||||
///
|
///
|
||||||
pub fn parse_float(comptime float: std.builtin.Type.Float, utf8: []const u8) ParseError!math.Float(float) {
|
pub fn parse_decimal(comptime Decimal: type, utf8: []const u8, format: DecimalFormat) !Decimal {
|
||||||
// ""
|
|
||||||
if (utf8.len == 0) {
|
if (utf8.len == 0) {
|
||||||
return error.BadSyntax;
|
return error.BadSyntax;
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_negative = utf8[0] == '-';
|
switch (@typeInfo(Decimal)) {
|
||||||
|
.Int => |int| {
|
||||||
|
var has_sign = switch (utf8[0]) {
|
||||||
|
'-', '+', ' ' => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
|
||||||
// "-"
|
var result = @as(Decimal, 0);
|
||||||
if (is_negative and (utf8.len == 1)) {
|
|
||||||
return error.BadSyntax;
|
|
||||||
}
|
|
||||||
|
|
||||||
const negative_offset = @boolToInt(is_negative);
|
for (@boolToInt(has_sign) .. utf8.len) |index| {
|
||||||
var has_decimal = utf8[negative_offset] == '.';
|
const radix = 10;
|
||||||
|
const code = utf8[index];
|
||||||
|
|
||||||
// "-."
|
switch (code) {
|
||||||
if (has_decimal and (utf8.len == 2)) {
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {
|
||||||
return error.BadSyntax;
|
result = try math.checked_add(
|
||||||
}
|
try math.checked_mul(result, radix),
|
||||||
|
try math.checked_sub(code, '0'));
|
||||||
|
},
|
||||||
|
|
||||||
const Float = math.Float(float);
|
else => {
|
||||||
var result: Float = 0;
|
if (format.delimiter.len == 0 or !io.equals(format.delimiter, utf8[index ..])) {
|
||||||
var factor: Float = 1;
|
return error.BadSyntax;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (utf8[0 .. negative_offset + @boolToInt(has_decimal)]) |code| switch (code) {
|
switch (int.signedness) {
|
||||||
'.' => {
|
.signed => {
|
||||||
if (has_decimal) return error.BadSyntax;
|
return result * @as(Decimal, if (has_sign and utf8[0] == '-') -1 else 1);
|
||||||
|
},
|
||||||
|
|
||||||
has_decimal = true;
|
.unsigned => {
|
||||||
|
if (has_sign and utf8[0] == '-') {
|
||||||
|
return error.OutOfMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {
|
.Float => {
|
||||||
if (has_decimal) factor /= 10.0;
|
// ""
|
||||||
|
if (utf8.len == 0) {
|
||||||
|
return error.BadSyntax;
|
||||||
|
}
|
||||||
|
|
||||||
result = ((result * 10.0) + @intToFloat(Float, code - '0'));
|
var has_sign = switch (utf8[0]) {
|
||||||
|
'-', '+', ' ' => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// "-"
|
||||||
|
if (has_sign and utf8.len == 1) {
|
||||||
|
return error.BadSyntax;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sign_offset = @boolToInt(has_sign);
|
||||||
|
var has_decimal = utf8[sign_offset] == '.';
|
||||||
|
|
||||||
|
// "-."
|
||||||
|
if (has_decimal and (utf8.len == 2)) {
|
||||||
|
return error.BadSyntax;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = @as(Decimal, 0);
|
||||||
|
var factor = @as(Decimal, if (has_sign and utf8[0] == '-') -1 else 1);
|
||||||
|
|
||||||
|
for (utf8[0 .. (sign_offset + @boolToInt(has_decimal))]) |code| switch (code) {
|
||||||
|
'.' => {
|
||||||
|
if (has_decimal) return error.BadSyntax;
|
||||||
|
|
||||||
|
has_decimal = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {
|
||||||
|
if (has_decimal) factor /= 10.0;
|
||||||
|
|
||||||
|
result = ((result * 10.0) + @intToFloat(Decimal, code - '0'));
|
||||||
|
},
|
||||||
|
|
||||||
|
else => return error.BadSyntax,
|
||||||
|
};
|
||||||
|
|
||||||
|
return result * factor;
|
||||||
},
|
},
|
||||||
|
|
||||||
else => return error.BadSyntax,
|
else => @compileError("`" ++ @typeName(Decimal) ++ "` cannot be formatted as a decimal string"),
|
||||||
};
|
|
||||||
|
|
||||||
return result * factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Attempts to parse an int value of type described by `int` from `utf8`, with `options` as additional rules for the
|
|
||||||
/// parsing logic to consider.
|
|
||||||
///
|
|
||||||
/// The function returns a [IntParseError] if `utf8` does not conform to the syntax of a float, does not match the rules
|
|
||||||
/// specified in `option`, or exceeds the maximum size of the int described by `int`.
|
|
||||||
///
|
|
||||||
pub fn parse_int(
|
|
||||||
comptime int: std.builtin.Type.Int,
|
|
||||||
utf8: []const u8,
|
|
||||||
options: IntParseOptions) IntParseError!math.Int(int) {
|
|
||||||
|
|
||||||
if (utf8.len == 0) {
|
|
||||||
return error.BadSyntax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
const is_negative = utf8[0] == '-';
|
|
||||||
|
|
||||||
switch (int.signedness) {
|
|
||||||
.signed => {
|
|
||||||
if (is_negative and utf8.len == 1) {
|
|
||||||
return error.BadSyntax;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.unsigned => {
|
|
||||||
if (is_negative) {
|
|
||||||
return error.BadSyntax;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = @as(math.Int(int), 0);
|
|
||||||
|
|
||||||
for (0 .. utf8.len) |index| {
|
|
||||||
const code = utf8[index];
|
|
||||||
|
|
||||||
switch (code) {
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {
|
|
||||||
result = try math.checked_add(try math.checked_mul(result, 10), try math.checked_sub(code, '0'));
|
|
||||||
},
|
|
||||||
|
|
||||||
else => {
|
|
||||||
if (options.delimiter.len == 0 or !io.equals(options.delimiter, utf8[index ..])) {
|
|
||||||
return error.BadSyntax;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -175,123 +153,146 @@ pub fn print(writer: io.Writer, utf8: []const u8) PrintError!void {
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub fn print_float(comptime float: std.builtin.Type.Float, writer: io.Writer, value: @Type(float)) PrintError!void {
|
pub fn print_formatted(writer: io.Writer, comptime format: []const u8, arguments: anytype) PrintError!void {
|
||||||
_ = writer;
|
switch (@typeInfo(@TypeOf(arguments))) {
|
||||||
_ = value;
|
.Struct => |arguments_struct| {
|
||||||
}
|
comptime var arg_index = 0;
|
||||||
|
comptime var head = 0;
|
||||||
|
comptime var tail = 0;
|
||||||
|
|
||||||
///
|
inline while (tail < format.len) : (tail += 1) {
|
||||||
/// Prints the format string `format` with all `{...}` placeholders substituted with the a value in `args` corresponding
|
if (format[tail] == '{') {
|
||||||
/// to the ordinality of each substitution.
|
if (tail > format.len) {
|
||||||
///
|
@compileError("expected an idenifier after opening `{`");
|
||||||
/// Specifiers may be placed inside `{}` to augment the behavior of the corresponding [FormatArg]. For example, to print
|
|
||||||
/// a float formatted with an integer component padding of `3`, a decimal padding of `2`, and a prefix for positives as
|
|
||||||
/// well as negatives, you may specify it as `{+3.2}`.
|
|
||||||
///
|
|
||||||
/// To prevent braces from being interpreted as format placeholders, simply double-brace them (`"{{"`) and the format
|
|
||||||
/// string will substitute them as a single brace.
|
|
||||||
///
|
|
||||||
/// *Note* the function assumes that, for every specifier in `format`, there is a corresponding [FormatArg] in `args`.
|
|
||||||
/// Further, any instance of `{` is assumed to be a placeholder and must be terminated with a corresponding `}` before
|
|
||||||
/// the end of string. Failure to meet any of these requirements will result in safety-checked runtime behavior.
|
|
||||||
///
|
|
||||||
pub fn print_formatted(writer: io.Writer, format: []const u8, args_formatter: ArgsFormatter) PrintError!void {
|
|
||||||
const usize_int = @typeInfo(usize).Int;
|
|
||||||
var head = @as(usize, 0);
|
|
||||||
var tail = @as(usize, 0);
|
|
||||||
var arg_index = @as(usize, 0);
|
|
||||||
|
|
||||||
while (tail < format.len) : (tail += 1) {
|
|
||||||
if (format[tail] == '{') {
|
|
||||||
debug.assert(tail < format.len);
|
|
||||||
|
|
||||||
tail += 1;
|
|
||||||
|
|
||||||
switch (format[tail]) {
|
|
||||||
'{' => {
|
|
||||||
try print(writer, format[head .. tail]);
|
|
||||||
|
|
||||||
tail += 1;
|
|
||||||
head = tail;
|
|
||||||
},
|
|
||||||
|
|
||||||
'}' => {
|
|
||||||
try print(writer, format[head .. tail]);
|
|
||||||
|
|
||||||
try args_formatter.invoke(.{
|
|
||||||
.index = arg_index,
|
|
||||||
.writer = writer,
|
|
||||||
});
|
|
||||||
|
|
||||||
arg_index += 1;
|
|
||||||
tail += 1;
|
|
||||||
head = tail;
|
|
||||||
},
|
|
||||||
|
|
||||||
else => {
|
|
||||||
try print(writer, format[head .. tail]);
|
|
||||||
|
|
||||||
tail += 1;
|
|
||||||
head = tail;
|
|
||||||
|
|
||||||
debug.assert(tail < format.len);
|
|
||||||
|
|
||||||
while (format[tail] != '}') {
|
|
||||||
tail += 1;
|
|
||||||
|
|
||||||
debug.assert(tail < format.len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const arg_index_name = format[head .. tail];
|
|
||||||
|
|
||||||
try args_formatter.invoke(.{
|
|
||||||
.index = parse_int(usize_int, arg_index_name, .{}) catch @panic("invalid arg index value"),
|
|
||||||
.writer = writer,
|
|
||||||
});
|
|
||||||
|
|
||||||
tail += 1;
|
tail += 1;
|
||||||
head = tail;
|
|
||||||
|
switch (format[tail]) {
|
||||||
|
'{' => {
|
||||||
|
try print(writer, format[head .. (tail - 1)]);
|
||||||
|
|
||||||
|
tail += 1;
|
||||||
|
head = tail;
|
||||||
|
},
|
||||||
|
|
||||||
|
'}' => {
|
||||||
|
if (!arguments_struct.is_tuple) {
|
||||||
|
@compileError("all format specifiers must be named when using a named struct");
|
||||||
|
}
|
||||||
|
|
||||||
|
try print(writer, arguments[arg_index]);
|
||||||
|
|
||||||
|
arg_index += 1;
|
||||||
|
tail += 1;
|
||||||
|
head = tail;
|
||||||
|
},
|
||||||
|
|
||||||
|
else => {
|
||||||
|
if (arguments_struct.is_tuple) {
|
||||||
|
@compileError("format specifiers cannot be named when using a tuple struct");
|
||||||
|
}
|
||||||
|
|
||||||
|
try print(writer, format[head .. (tail - 1)]);
|
||||||
|
|
||||||
|
head = tail;
|
||||||
|
tail += 1;
|
||||||
|
|
||||||
|
if (tail >= format.len) {
|
||||||
|
@compileError("expected closing `}` or another `{` after opening `{`");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug.assert(tail < format.len);
|
||||||
|
|
||||||
|
inline while (format[tail] != '}') {
|
||||||
|
tail += 1;
|
||||||
|
|
||||||
|
debug.assert(tail < format.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
try print_value(writer, @field(arguments, format[head .. tail]));
|
||||||
|
|
||||||
|
tail += 1;
|
||||||
|
head = tail;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
else => @compileError("`arguments` must be a struct type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to print the int `value` described by `int` to `writer`.
|
|
||||||
///
|
///
|
||||||
/// The function returns [PrintError] if the write failed to complete partially or entirely.
|
|
||||||
///
|
///
|
||||||
pub fn print_int(comptime int: std.builtin.Type.Int, writer: io.Writer, value: math.Int(int)) PrintError!void {
|
pub fn print_decimal(writer: io.Writer, value: anytype, format: DecimalFormat) PrintError!void {
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
return try print(writer, "0");
|
return print(writer, switch (format.positive_prefix) {
|
||||||
|
.none => "0",
|
||||||
|
.plus => "+0",
|
||||||
|
.space => " 0",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Don't make this buffer arbitrarily size cause big int types WILL overflow.
|
switch (@typeInfo(@TypeOf(value))) {
|
||||||
var buffer = [_]u8{0} ** 40;
|
.Int => |int| {
|
||||||
var buffer_count: usize = 0;
|
const radix = 10;
|
||||||
var split_value = value;
|
var buffer = [_]u8{0} ** (1 + math.max(int.bits, 1));
|
||||||
|
var buffer_start = buffer.len - 1;
|
||||||
|
|
||||||
if ((int.signedness == .unsigned) and (value < 0)) {
|
{
|
||||||
buffer[0] = '-';
|
var decomposable_value = value;
|
||||||
buffer_count += 1;
|
|
||||||
|
while (decomposable_value != 0) : (buffer_start -= 1) {
|
||||||
|
buffer[buffer_start] = @intCast(u8, (decomposable_value % radix) + '0');
|
||||||
|
decomposable_value = (decomposable_value / radix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int.signedness == .unsigned and value < 0) {
|
||||||
|
buffer[buffer_start] = '-';
|
||||||
|
} else {
|
||||||
|
switch (format.positive_prefix) {
|
||||||
|
.none => buffer_start += 1,
|
||||||
|
.plus => buffer[buffer_start] = '+',
|
||||||
|
.space => buffer[buffer_start] = ' ',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try print(writer, buffer[buffer_start ..]);
|
||||||
|
},
|
||||||
|
|
||||||
|
else => @compileError("`arguments` must be a struct type"),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
while (split_value != 0) : (buffer_count += 1) {
|
|
||||||
const radix = 10;
|
pub fn print_hexadecimal(writer: io.Writer, value: anytype, format: HexadecimalFormat) PrintError!void {
|
||||||
|
// TODO: Implement.
|
||||||
buffer[buffer_count] = @intCast(u8, (split_value % radix) + '0');
|
_ = writer;
|
||||||
split_value = (split_value / radix);
|
_ = value;
|
||||||
}
|
_ = format;
|
||||||
|
|
||||||
{
|
unreachable;
|
||||||
const half_buffer_count = buffer_count / 2;
|
}
|
||||||
var index: usize = 0;
|
|
||||||
|
noinline fn print_value(writer: io.Writer, value: anytype) PrintError!void {
|
||||||
while (index < half_buffer_count) : (index += 1) {
|
const Value = @TypeOf(value);
|
||||||
io.swap(u8, &buffer[index], &buffer[buffer_count - index - 1]);
|
|
||||||
}
|
return switch (@typeInfo(Value)) {
|
||||||
}
|
.Int => print_decimal(writer, value, .{}),
|
||||||
|
.Float => print_decimal(writer, value, .{}),
|
||||||
try print(writer, buffer[0 .. buffer_count]);
|
|
||||||
|
.Pointer => |pointer| switch (pointer.size) {
|
||||||
|
.One, .Many, .C => print_hexadecimal(writer, @ptrToInt(value), .{}),
|
||||||
|
.Slice => if (pointer.child == u8) print(writer, value) else @compileError(unformattableMessage(Value)),
|
||||||
|
},
|
||||||
|
|
||||||
|
else => @compileError(unformattableMessage(Value)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unformattableMessage(comptime Value: type) []const u8 {
|
||||||
|
return "`" ++ @typeName(Value) ++ "` are not formattable";
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,7 +189,7 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) types.ParseError!Expr
|
||||||
_ = tokenizer.step(.{.include_newlines = false});
|
_ = tokenizer.step(.{.include_newlines = false});
|
||||||
|
|
||||||
return Expression{
|
return Expression{
|
||||||
.integer_literal = coral.utf8.parse_int(@typeInfo(types.Integer).Int, value, .{}) catch |parse_error| {
|
.integer_literal = coral.utf8.parse_decimal(types.Integer, value, .{}) catch |parse_error| {
|
||||||
return self.fail_syntax(switch (parse_error) {
|
return self.fail_syntax(switch (parse_error) {
|
||||||
error.BadSyntax => "invalid integer literal",
|
error.BadSyntax => "invalid integer literal",
|
||||||
error.IntOverflow => "integer literal is too big",
|
error.IntOverflow => "integer literal is too big",
|
||||||
|
@ -202,7 +202,7 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) types.ParseError!Expr
|
||||||
_ = tokenizer.step(.{.include_newlines = false});
|
_ = tokenizer.step(.{.include_newlines = false});
|
||||||
|
|
||||||
return Expression{
|
return Expression{
|
||||||
.float_literal = coral.utf8.parse_float(@typeInfo(types.Float).Float, value) catch |parse_error| {
|
.float_literal = coral.utf8.parse_decimal(types.Float, value, .{}) catch |parse_error| {
|
||||||
return self.fail_syntax(switch (parse_error) {
|
return self.fail_syntax(switch (parse_error) {
|
||||||
error.BadSyntax => "invalid float literal",
|
error.BadSyntax => "invalid float literal",
|
||||||
});
|
});
|
||||||
|
|
|
@ -59,25 +59,15 @@ pub fn compile(self: *Self, data: []const u8) types.RuntimeError!void {
|
||||||
var tokenizer = tokens.Tokenizer{.source = data};
|
var tokenizer = tokens.Tokenizer{.source = data};
|
||||||
|
|
||||||
ast.parse(&tokenizer) catch |init_error| {
|
ast.parse(&tokenizer) catch |init_error| {
|
||||||
if (init_error == error.OutOfMemory) {
|
if (init_error == error.BadSyntax) {
|
||||||
self.clear_error_details();
|
self.clear_error_details();
|
||||||
|
|
||||||
try self.message_data.push_all(self.env.allocator, "@(");
|
|
||||||
|
|
||||||
var message_buffer = self.message_data.as_buffer(self.env.allocator);
|
var message_buffer = self.message_data.as_buffer(self.env.allocator);
|
||||||
const message_writer = message_buffer.as_writer();
|
|
||||||
|
|
||||||
coral.utf8.print_int(@typeInfo(usize).Int, message_writer, tokenizer.lines_stepped) catch {
|
coral.utf8.print_formatted(message_buffer.as_writer(), "@({line}): {name}", .{
|
||||||
return error.OutOfMemory;
|
.line = tokenizer.lines_stepped,
|
||||||
};
|
.name = ast.error_message,
|
||||||
|
}) catch return error.OutOfMemory;
|
||||||
coral.utf8.print(message_writer, "): ") catch {
|
|
||||||
return error.OutOfMemory;
|
|
||||||
};
|
|
||||||
|
|
||||||
coral.utf8.print(message_writer, ast.error_message) catch {
|
|
||||||
return error.OutOfMemory;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return init_error;
|
return init_error;
|
||||||
|
@ -216,7 +206,7 @@ pub fn emit_opcode(self: *Self, opcode: Opcode) coral.io.AllocationError!void {
|
||||||
pub fn error_details(self: Self) []const u8 {
|
pub fn error_details(self: Self) []const u8 {
|
||||||
coral.debug.assert(self.message_data.values.len >= self.message_name_len);
|
coral.debug.assert(self.message_data.values.len >= self.message_name_len);
|
||||||
|
|
||||||
return self.message_data.values[self.message_name_len .. ];
|
return self.message_data.values;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(env: *Environment, chunk_name: []const u8) coral.io.AllocationError!Self {
|
pub fn init(env: *Environment, chunk_name: []const u8) coral.io.AllocationError!Self {
|
||||||
|
|
|
@ -91,8 +91,6 @@ pub const Tokenizer = struct {
|
||||||
include_newlines: bool,
|
include_newlines: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const default_token = Token{.unknown = 0};
|
|
||||||
|
|
||||||
pub fn step(self: *Tokenizer, options: StepOptions) bool {
|
pub fn step(self: *Tokenizer, options: StepOptions) bool {
|
||||||
var cursor = @as(usize, 0);
|
var cursor = @as(usize, 0);
|
||||||
|
|
||||||
|
@ -114,11 +112,10 @@ pub const Tokenizer = struct {
|
||||||
|
|
||||||
'\n' => {
|
'\n' => {
|
||||||
cursor += 1;
|
cursor += 1;
|
||||||
|
self.current_token = .newline;
|
||||||
|
self.lines_stepped += 1;
|
||||||
|
|
||||||
if (options.include_newlines) {
|
if (options.include_newlines) {
|
||||||
self.lines_stepped += 1;
|
|
||||||
self.current_token = .newline;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,10 +3,5 @@ const coral = @import("coral");
|
||||||
const ona = @import("ona");
|
const ona = @import("ona");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var data = [_]u8{0} ** 32;
|
|
||||||
var fixed_buffer = coral.io.FixedBuffer{.slice = &data};
|
|
||||||
|
|
||||||
try coral.utf8.print_formatted(fixed_buffer.as_writer(), "hello, {}", coral.utf8.format_args(.{"world"}));
|
|
||||||
|
|
||||||
ona.run_app(.{.sandboxed_path = &ona.file.Path.cwd});
|
ona.run_app(.{.sandboxed_path = &ona.file.Path.cwd});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue