mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
parsing error value decls and error value literals
and return with '?' or '%' prefix
This commit is contained in:
parent
82d1b51b1d
commit
5e212db29c
@ -5,9 +5,11 @@
|
||||
```
|
||||
Root : many(TopLevelDecl) "EOF"
|
||||
|
||||
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration
|
||||
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
|
||||
|
||||
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
|
||||
ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
|
||||
|
||||
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
|
||||
|
||||
ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
|
||||
|
||||
@ -77,7 +79,7 @@ ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expre
|
||||
|
||||
BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression
|
||||
|
||||
ReturnExpression : "return" option(Expression)
|
||||
ReturnExpression : option("%" | "?") "return" option(Expression)
|
||||
|
||||
IfExpression : IfVarExpression | IfBoolExpression
|
||||
|
||||
@ -133,7 +135,7 @@ StructLiteralField : "." "Symbol" "=" Expression
|
||||
|
||||
PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?"
|
||||
|
||||
PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression
|
||||
PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
|
||||
|
||||
ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
|
||||
|
||||
@ -148,7 +150,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue"
|
||||
|
||||
```
|
||||
x() x[] x.y
|
||||
!x -x ~x *x &x ?x
|
||||
!x -x ~x *x &x ?x %x
|
||||
x{}
|
||||
* / %
|
||||
+ -
|
||||
@ -199,12 +201,20 @@ c_ulonglong unsigned long long for ABI compatibility with C
|
||||
### Boolean Type
|
||||
The boolean type has the name `bool` and represents either true or false.
|
||||
|
||||
### Function Types
|
||||
### Function Type
|
||||
TODO
|
||||
|
||||
### Array Types
|
||||
TODO
|
||||
Also, are there slices?
|
||||
### Fixed-Size Array Type
|
||||
|
||||
Example: The string `"aoeu"` has type `[4]u8`.
|
||||
|
||||
The size is known at compile time and is part of the type.
|
||||
|
||||
### Slice Type
|
||||
|
||||
A slice can be obtained with the slicing syntax: `array[start...end]`
|
||||
|
||||
Example: `"aoeu"[0...2]` has type `[]u8`.
|
||||
|
||||
### Struct Types
|
||||
TODO
|
||||
@ -213,10 +223,13 @@ TODO
|
||||
TODO
|
||||
|
||||
### Unreachable Type
|
||||
|
||||
The unreachable type has the name `unreachable`. TODO explanation
|
||||
|
||||
### Void Type
|
||||
The void type has the name `void`. TODO explanation
|
||||
|
||||
The void type has the name `void`. void types are zero bits and are omitted
|
||||
from codegen.
|
||||
|
||||
|
||||
## Expressions
|
||||
|
||||
@ -3,50 +3,50 @@ export executable "cat";
|
||||
import "std.zig";
|
||||
|
||||
// Things to do to make this work:
|
||||
// * isize instead of usize for things
|
||||
// * var args printing
|
||||
// * update std API
|
||||
// * !void type
|
||||
// * %void type
|
||||
// * defer
|
||||
// * !return
|
||||
// * !! operator
|
||||
// * make main return !void
|
||||
// * how to reference error values (!void).Invalid ? !Invalid ?
|
||||
// * ~ is bool not, not !
|
||||
// * %return
|
||||
// * %% operator
|
||||
// * make main return %void
|
||||
// * how to reference error values %.Invalid
|
||||
// * cast err type to string
|
||||
// * update std API
|
||||
|
||||
pub fn main(args: [][]u8) !void => {
|
||||
pub %.Invalid;
|
||||
|
||||
pub fn main(args: [][]u8) %void => {
|
||||
const exe = args[0];
|
||||
var catted_anything = false;
|
||||
for (arg, args[1...]) {
|
||||
if (arg == "-") {
|
||||
catted_anything = true;
|
||||
!return cat_stream(stdin);
|
||||
%return cat_stream(stdin);
|
||||
} else if (arg[0] == '-') {
|
||||
return usage(exe);
|
||||
} else {
|
||||
var is: InputStream;
|
||||
is.open(arg, OpenReadOnly) !! (err) => {
|
||||
is.open(arg, OpenReadOnly) %% (err) => {
|
||||
stderr.print("Unable to open file: {}", ([]u8])(err));
|
||||
return err;
|
||||
}
|
||||
defer is.close();
|
||||
|
||||
catted_anything = true;
|
||||
!return cat_stream(is);
|
||||
%return cat_stream(is);
|
||||
}
|
||||
}
|
||||
if (~catted_anything) {
|
||||
!return cat_stream(stdin)
|
||||
if (!catted_anything) {
|
||||
%return cat_stream(stdin)
|
||||
}
|
||||
}
|
||||
|
||||
fn usage(exe: []u8) !void => {
|
||||
fn usage(exe: []u8) %void => {
|
||||
stderr.print("Usage: {} [FILE]...\n", exe);
|
||||
return !Invalid;
|
||||
return %.Invalid;
|
||||
}
|
||||
|
||||
fn cat_stream(is: InputStream) !void => {
|
||||
fn cat_stream(is: InputStream) %void => {
|
||||
var buf: [1024 * 4]u8;
|
||||
|
||||
while (true) {
|
||||
|
||||
@ -3,6 +3,7 @@ export executable "hello";
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
//stderr.print_str("Hello, world!\n");
|
||||
print_str("Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -129,10 +129,12 @@ enum NodeType {
|
||||
NodeTypeDirective,
|
||||
NodeTypeReturnExpr,
|
||||
NodeTypeVariableDeclaration,
|
||||
NodeTypeErrorValueDecl,
|
||||
NodeTypeBinOpExpr,
|
||||
NodeTypeNumberLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
NodeTypeCharLiteral,
|
||||
NodeTypeErrorLiteral,
|
||||
NodeTypeSymbol,
|
||||
NodeTypePrefixOpExpr,
|
||||
NodeTypeFnCallExpr,
|
||||
@ -222,7 +224,14 @@ struct AstNodeBlock {
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
enum ReturnKind {
|
||||
ReturnKindUnconditional,
|
||||
ReturnKindMaybe,
|
||||
ReturnKindError,
|
||||
};
|
||||
|
||||
struct AstNodeReturnExpr {
|
||||
ReturnKind kind;
|
||||
// might be null in case of return void;
|
||||
AstNode *expr;
|
||||
|
||||
@ -243,6 +252,14 @@ struct AstNodeVariableDeclaration {
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeErrorValueDecl {
|
||||
VisibMod visib_mod;
|
||||
Buf name;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TopLevelDecl top_level_decl;
|
||||
};
|
||||
|
||||
enum BinOpType {
|
||||
BinOpTypeInvalid,
|
||||
BinOpTypeAssign,
|
||||
@ -358,6 +375,7 @@ enum PrefixOp {
|
||||
PrefixOpConstAddressOf,
|
||||
PrefixOpDereference,
|
||||
PrefixOpMaybe,
|
||||
PrefixOpError,
|
||||
};
|
||||
|
||||
struct AstNodePrefixOpExpr {
|
||||
@ -564,6 +582,14 @@ struct AstNodeNumberLiteral {
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeErrorLiteral {
|
||||
Buf symbol;
|
||||
|
||||
// populated by semantic analyzer
|
||||
NumLitCodeGen codegen;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeStructValueField {
|
||||
Buf name;
|
||||
AstNode *expr;
|
||||
@ -644,6 +670,7 @@ struct AstNode {
|
||||
AstNodeBlock block;
|
||||
AstNodeReturnExpr return_expr;
|
||||
AstNodeVariableDeclaration variable_declaration;
|
||||
AstNodeErrorValueDecl error_value_decl;
|
||||
AstNodeBinOpExpr bin_op_expr;
|
||||
AstNodeExternBlock extern_block;
|
||||
AstNodeDirective directive;
|
||||
@ -668,6 +695,7 @@ struct AstNode {
|
||||
AstNodeStringLiteral string_literal;
|
||||
AstNodeCharLiteral char_literal;
|
||||
AstNodeNumberLiteral number_literal;
|
||||
AstNodeErrorLiteral error_literal;
|
||||
AstNodeContainerInitExpr container_init_expr;
|
||||
AstNodeStructValueField struct_val_field;
|
||||
AstNodeNullLiteral null_literal;
|
||||
@ -738,6 +766,10 @@ struct TypeTableEntryMaybe {
|
||||
TypeTableEntry *child_type;
|
||||
};
|
||||
|
||||
struct TypeTableEntryError {
|
||||
TypeTableEntry *child_type;
|
||||
};
|
||||
|
||||
struct TypeTableEntryEnum {
|
||||
AstNode *decl_node;
|
||||
uint32_t field_count;
|
||||
@ -778,6 +810,7 @@ enum TypeTableEntryId {
|
||||
TypeTableEntryIdStruct,
|
||||
TypeTableEntryIdNumberLiteral,
|
||||
TypeTableEntryIdMaybe,
|
||||
TypeTableEntryIdError,
|
||||
TypeTableEntryIdEnum,
|
||||
TypeTableEntryIdFn,
|
||||
};
|
||||
@ -799,6 +832,7 @@ struct TypeTableEntry {
|
||||
TypeTableEntryStruct structure;
|
||||
TypeTableEntryNumLit num_lit;
|
||||
TypeTableEntryMaybe maybe;
|
||||
TypeTableEntryError error;
|
||||
TypeTableEntryEnum enumeration;
|
||||
TypeTableEntryFn fn;
|
||||
} data;
|
||||
@ -808,6 +842,7 @@ struct TypeTableEntry {
|
||||
TypeTableEntry *unknown_size_array_parent[2];
|
||||
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
|
||||
TypeTableEntry *maybe_parent;
|
||||
TypeTableEntry *error_parent;
|
||||
};
|
||||
|
||||
struct ImporterInfo {
|
||||
|
||||
172
src/analyze.cpp
172
src/analyze.cpp
@ -43,7 +43,9 @@ static AstNode *first_executing_node(AstNode *node) {
|
||||
case NodeTypeDirective:
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeVariableDeclaration:
|
||||
case NodeTypeErrorValueDecl:
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeErrorLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeSymbol:
|
||||
@ -104,6 +106,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
||||
case TypeTableEntryIdNumberLiteral:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdError:
|
||||
// nothing to init
|
||||
break;
|
||||
case TypeTableEntryIdStruct:
|
||||
@ -215,6 +218,57 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
|
||||
if (child_type->error_parent) {
|
||||
return child_type->error_parent;
|
||||
} else {
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError);
|
||||
zig_panic("TODO get_error_type");
|
||||
// create a struct with a boolean whether this is the null value
|
||||
assert(child_type->type_ref);
|
||||
LLVMTypeRef elem_types[] = {
|
||||
child_type->type_ref,
|
||||
LLVMInt1Type(),
|
||||
};
|
||||
entry->type_ref = LLVMStructType(elem_types, 2, false);
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
|
||||
entry->size_in_bits = child_type->size_in_bits + 8;
|
||||
entry->align_in_bits = child_type->align_in_bits;
|
||||
assert(child_type->di_type);
|
||||
|
||||
|
||||
LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
|
||||
LLVMZigDIFile *di_file = nullptr;
|
||||
unsigned line = 0;
|
||||
entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
|
||||
LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
|
||||
compile_unit_scope, di_file, line);
|
||||
|
||||
LLVMZigDIType *di_element_types[] = {
|
||||
LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
|
||||
"val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
|
||||
child_type->di_type),
|
||||
LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
|
||||
"maybe", di_file, line, 8, 8, 8, 0,
|
||||
child_type->di_type),
|
||||
};
|
||||
LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
|
||||
compile_unit_scope,
|
||||
buf_ptr(&entry->name),
|
||||
di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
|
||||
nullptr, di_element_types, 2, 0, nullptr, "");
|
||||
|
||||
LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
|
||||
entry->di_type = replacement_di_type;
|
||||
|
||||
entry->data.maybe.child_type = child_type;
|
||||
|
||||
child_type->maybe_parent = entry;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size)
|
||||
{
|
||||
auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
|
||||
@ -922,6 +976,11 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
g->global_vars.append(var);
|
||||
break;
|
||||
}
|
||||
case NodeTypeErrorValueDecl:
|
||||
{
|
||||
zig_panic("TODO resolve_top_level_decl NodeTypeErrorValueDecl");
|
||||
break;
|
||||
}
|
||||
case NodeTypeUse:
|
||||
// nothing to do here
|
||||
break;
|
||||
@ -937,6 +996,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeErrorLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeBoolLiteral:
|
||||
@ -1005,6 +1065,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdError:
|
||||
return false;
|
||||
case TypeTableEntryIdInt:
|
||||
if (is_num_lit_unsigned(num_lit)) {
|
||||
@ -2263,6 +2324,12 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
zig_panic("TODO analyze_error_literal_expr");
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
@ -3021,7 +3088,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
||||
if (meta_type->id == TypeTableEntryIdInvalid) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else if (meta_type->id == TypeTableEntryIdUnreachable) {
|
||||
add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed"));
|
||||
add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in maybe type"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type));
|
||||
@ -3034,6 +3101,31 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
||||
return get_maybe_type(g, type_entry);
|
||||
}
|
||||
}
|
||||
case PrefixOpError:
|
||||
{
|
||||
TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInvalid) {
|
||||
return type_entry;
|
||||
} else if (type_entry->id == TypeTableEntryIdMetaType) {
|
||||
TypeTableEntry *meta_type = resolve_type(g, expr_node);
|
||||
if (meta_type->id == TypeTableEntryIdInvalid) {
|
||||
return meta_type;
|
||||
} else if (meta_type->id == TypeTableEntryIdUnreachable) {
|
||||
add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in error type"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type));
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdUnreachable) {
|
||||
add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in error type"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
// TODO eval const expr
|
||||
return get_error_type(g, type_entry);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -3099,6 +3191,37 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
if (!context->fn_entry) {
|
||||
add_node_error(g, node, buf_sprintf("return expression outside function definition"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (node->data.return_expr.kind != ReturnKindUnconditional) {
|
||||
zig_panic("TODO analyze_return_expr conditional");
|
||||
}
|
||||
|
||||
TypeTableEntry *expected_return_type = get_return_type(context);
|
||||
TypeTableEntry *actual_return_type;
|
||||
if (node->data.return_expr.expr) {
|
||||
actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
|
||||
} else {
|
||||
actual_return_type = g->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
if (actual_return_type->id == TypeTableEntryIdUnreachable) {
|
||||
// "return exit(0)" should just be "exit(0)".
|
||||
add_node_error(g, node, buf_sprintf("returning is unreachable"));
|
||||
actual_return_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type);
|
||||
|
||||
return g->builtin_types.entry_unreachable;
|
||||
}
|
||||
|
||||
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
@ -3140,29 +3263,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||
}
|
||||
|
||||
case NodeTypeReturnExpr:
|
||||
{
|
||||
if (context->fn_entry) {
|
||||
TypeTableEntry *expected_return_type = get_return_type(context);
|
||||
TypeTableEntry *actual_return_type;
|
||||
if (node->data.return_expr.expr) {
|
||||
actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
|
||||
} else {
|
||||
actual_return_type = g->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
if (actual_return_type->id == TypeTableEntryIdUnreachable) {
|
||||
// "return exit(0)" should just be "exit(0)".
|
||||
add_node_error(g, node, buf_sprintf("returning is unreachable"));
|
||||
actual_return_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type);
|
||||
} else {
|
||||
add_node_error(g, node, buf_sprintf("return expression outside function definition"));
|
||||
}
|
||||
return_type = g->builtin_types.entry_unreachable;
|
||||
break;
|
||||
}
|
||||
return_type = analyze_return_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeVariableDeclaration:
|
||||
analyze_variable_declaration(g, import, context, expected_type, node);
|
||||
return_type = g->builtin_types.entry_void;
|
||||
@ -3236,6 +3338,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||
case NodeTypeNumberLiteral:
|
||||
return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeErrorLiteral:
|
||||
return_type = analyze_error_literal_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeStringLiteral:
|
||||
if (node->data.string_literal.c) {
|
||||
return_type = g->builtin_types.entry_c_string_literal;
|
||||
@ -3294,6 +3399,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||
case NodeTypeStructDecl:
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeErrorValueDecl:
|
||||
zig_unreachable();
|
||||
}
|
||||
assert(return_type);
|
||||
@ -3411,6 +3517,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeExternBlock:
|
||||
case NodeTypeUse:
|
||||
case NodeTypeVariableDeclaration:
|
||||
case NodeTypeErrorValueDecl:
|
||||
// already took care of these
|
||||
break;
|
||||
case NodeTypeDirective:
|
||||
@ -3425,6 +3532,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeErrorLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeBoolLiteral:
|
||||
@ -3457,6 +3565,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
{
|
||||
switch (node->type) {
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeErrorLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeBoolLiteral:
|
||||
@ -3464,6 +3573,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeGoto:
|
||||
case NodeTypeBreak:
|
||||
case NodeTypeContinue:
|
||||
case NodeTypeErrorValueDecl:
|
||||
// no dependencies on other top level declarations
|
||||
break;
|
||||
case NodeTypeSymbol:
|
||||
@ -3758,6 +3868,10 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
|
||||
case NodeTypeUse:
|
||||
// already taken care of
|
||||
break;
|
||||
case NodeTypeErrorValueDecl:
|
||||
// error value declarations do not depend on other top level decls
|
||||
resolve_top_level_decl(g, import, node);
|
||||
break;
|
||||
case NodeTypeDirective:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeFnDecl:
|
||||
@ -3769,6 +3883,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeErrorLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeBoolLiteral:
|
||||
@ -3966,6 +4081,8 @@ Expr *get_resolved_expr(AstNode *node) {
|
||||
return &node->data.container_init_expr.resolved_expr;
|
||||
case NodeTypeNumberLiteral:
|
||||
return &node->data.number_literal.resolved_expr;
|
||||
case NodeTypeErrorLiteral:
|
||||
return &node->data.error_literal.resolved_expr;
|
||||
case NodeTypeStringLiteral:
|
||||
return &node->data.string_literal.resolved_expr;
|
||||
case NodeTypeBlock:
|
||||
@ -4006,6 +4123,7 @@ Expr *get_resolved_expr(AstNode *node) {
|
||||
case NodeTypeStructDecl:
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeErrorValueDecl:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -4015,6 +4133,8 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeNumberLiteral:
|
||||
return &node->data.number_literal.codegen;
|
||||
case NodeTypeErrorLiteral:
|
||||
return &node->data.error_literal.codegen;
|
||||
case NodeTypeFnCallExpr:
|
||||
return &node->data.fn_call_expr.resolved_num_lit;
|
||||
case NodeTypeReturnExpr:
|
||||
@ -4056,6 +4176,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorValueDecl:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -4069,7 +4190,10 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
|
||||
return &node->data.fn_proto.top_level_decl;
|
||||
case NodeTypeStructDecl:
|
||||
return &node->data.struct_decl.top_level_decl;
|
||||
case NodeTypeErrorValueDecl:
|
||||
return &node->data.error_value_decl.top_level_decl;
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeErrorLiteral:
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
|
||||
@ -829,6 +829,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
|
||||
{
|
||||
zig_panic("TODO codegen PrefixOpMaybe");
|
||||
}
|
||||
case PrefixOpError:
|
||||
{
|
||||
zig_panic("TODO codegen PrefixOpError");
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -1937,6 +1941,12 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_error_literal(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeErrorLiteral);
|
||||
|
||||
zig_panic("TODO gen_error_literal");
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeSymbol);
|
||||
VariableTableEntry *variable = node->data.symbol_expr.variable;
|
||||
@ -2070,6 +2080,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
return gen_asm_expr(g, node);
|
||||
case NodeTypeNumberLiteral:
|
||||
return gen_number_literal(g, node);
|
||||
case NodeTypeErrorLiteral:
|
||||
return gen_error_literal(g, node);
|
||||
case NodeTypeStringLiteral:
|
||||
{
|
||||
Buf *str = &node->data.string_literal.buf;
|
||||
@ -2125,6 +2137,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
case NodeTypeArrayType:
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
case NodeTypeErrorValueDecl:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
|
||||
175
src/parser.cpp
175
src/parser.cpp
@ -63,6 +63,16 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
|
||||
case PrefixOpConstAddressOf: return "&const";
|
||||
case PrefixOpDereference: return "*";
|
||||
case PrefixOpMaybe: return "?";
|
||||
case PrefixOpError: return "%";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static const char *return_prefix_str(ReturnKind kind) {
|
||||
switch (kind) {
|
||||
case ReturnKindError: return "%";
|
||||
case ReturnKindMaybe: return "?";
|
||||
case ReturnKindUnconditional: return "";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -99,8 +109,12 @@ const char *node_type_str(NodeType node_type) {
|
||||
return "ReturnExpr";
|
||||
case NodeTypeVariableDeclaration:
|
||||
return "VariableDeclaration";
|
||||
case NodeTypeErrorValueDecl:
|
||||
return "ErrorValueDecl";
|
||||
case NodeTypeNumberLiteral:
|
||||
return "NumberLiteral";
|
||||
case NodeTypeErrorLiteral:
|
||||
return "ErrorLiteral";
|
||||
case NodeTypeStringLiteral:
|
||||
return "StringLiteral";
|
||||
case NodeTypeCharLiteral:
|
||||
@ -214,10 +228,13 @@ void ast_print(AstNode *node, int indent) {
|
||||
break;
|
||||
}
|
||||
case NodeTypeReturnExpr:
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
if (node->data.return_expr.expr)
|
||||
ast_print(node->data.return_expr.expr, indent + 2);
|
||||
break;
|
||||
{
|
||||
const char *prefix_str = return_prefix_str(node->data.return_expr.kind);
|
||||
fprintf(stderr, "%s%s\n", prefix_str, node_type_str(node->type));
|
||||
if (node->data.return_expr.expr)
|
||||
ast_print(node->data.return_expr.expr, indent + 2);
|
||||
break;
|
||||
}
|
||||
case NodeTypeVariableDeclaration:
|
||||
{
|
||||
Buf *name_buf = &node->data.variable_declaration.symbol;
|
||||
@ -228,6 +245,12 @@ void ast_print(AstNode *node, int indent) {
|
||||
ast_print(node->data.variable_declaration.expr, indent + 2);
|
||||
break;
|
||||
}
|
||||
case NodeTypeErrorValueDecl:
|
||||
{
|
||||
Buf *name_buf = &node->data.error_value_decl.name;
|
||||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
|
||||
break;
|
||||
}
|
||||
case NodeTypeExternBlock:
|
||||
{
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
@ -288,6 +311,11 @@ void ast_print(AstNode *node, int indent) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeTypeErrorLiteral:
|
||||
{
|
||||
fprintf(stderr, "%s '%s'", node_type_str(node->type), buf_ptr(&node->data.error_literal.symbol));
|
||||
break;
|
||||
}
|
||||
case NodeTypeStringLiteral:
|
||||
{
|
||||
const char *c = node->data.string_literal.c ? "c" : "";
|
||||
@ -1345,7 +1373,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
|
||||
}
|
||||
|
||||
/*
|
||||
PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
|
||||
PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
|
||||
KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
|
||||
*/
|
||||
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
@ -1415,6 +1443,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
||||
|
||||
ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
|
||||
return node;
|
||||
} else if (token->id == TokenIdPercentDot) {
|
||||
*token_index += 1;
|
||||
Token *symbol_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
|
||||
AstNode *node = ast_create_node(pc, NodeTypeErrorLiteral, token);
|
||||
ast_buf_from_token(pc, symbol_tok, &node->data.error_literal.symbol);
|
||||
return node;
|
||||
}
|
||||
|
||||
AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
|
||||
@ -1612,6 +1646,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
|
||||
case TokenIdAmpersand: return PrefixOpAddressOf;
|
||||
case TokenIdStar: return PrefixOpDereference;
|
||||
case TokenIdMaybe: return PrefixOpMaybe;
|
||||
case TokenIdPercent: return PrefixOpError;
|
||||
case TokenIdBoolAnd: return PrefixOpAddressOf;
|
||||
default: return PrefixOpInvalid;
|
||||
}
|
||||
@ -2031,20 +2066,46 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
|
||||
}
|
||||
|
||||
/*
|
||||
ReturnExpression : token(Return) option(Expression)
|
||||
ReturnExpression : option("%" | "?") "return" option(Expression)
|
||||
*/
|
||||
static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *return_tok = &pc->tokens->at(*token_index);
|
||||
if (return_tok->id == TokenIdKeywordReturn) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
|
||||
ReturnKind kind;
|
||||
|
||||
if (token->id == TokenIdPercent) {
|
||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
||||
if (next_token->id == TokenIdKeywordReturn) {
|
||||
kind = ReturnKindError;
|
||||
*token_index += 2;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (token->id == TokenIdMaybe) {
|
||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
||||
if (next_token->id == TokenIdKeywordReturn) {
|
||||
kind = ReturnKindMaybe;
|
||||
*token_index += 2;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (token->id == TokenIdKeywordReturn) {
|
||||
kind = ReturnKindUnconditional;
|
||||
*token_index += 1;
|
||||
AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok);
|
||||
node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
|
||||
return node;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, return_tok);
|
||||
ast_invalid_token_error(pc, token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, token);
|
||||
node->data.return_expr.kind = kind;
|
||||
node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2054,27 +2115,46 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
|
||||
VisibMod visib_mod;
|
||||
bool is_const;
|
||||
|
||||
if (first_token->id == TokenIdKeywordPub) {
|
||||
*token_index += 1;
|
||||
visib_mod = VisibModPub;
|
||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
||||
if (next_token->id == TokenIdKeywordVar ||
|
||||
next_token->id == TokenIdKeywordConst)
|
||||
{
|
||||
visib_mod = VisibModPub;
|
||||
is_const = (next_token->id == TokenIdKeywordConst);
|
||||
*token_index += 2;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, next_token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (first_token->id == TokenIdKeywordExport) {
|
||||
*token_index += 1;
|
||||
visib_mod = VisibModExport;
|
||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
||||
if (next_token->id == TokenIdKeywordVar ||
|
||||
next_token->id == TokenIdKeywordConst)
|
||||
{
|
||||
visib_mod = VisibModExport;
|
||||
is_const = (next_token->id == TokenIdKeywordConst);
|
||||
*token_index += 2;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, next_token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (first_token->id == TokenIdKeywordVar ||
|
||||
first_token->id == TokenIdKeywordConst)
|
||||
{
|
||||
visib_mod = VisibModPrivate;
|
||||
is_const = (first_token->id == TokenIdKeywordConst);
|
||||
*token_index += 1;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, first_token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Token *var_or_const_tok = &pc->tokens->at(*token_index);
|
||||
bool is_const = (var_or_const_tok->id == TokenIdKeywordConst);
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, first_token);
|
||||
|
||||
node->data.variable_declaration.is_const = is_const;
|
||||
@ -2836,7 +2916,54 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
|
||||
}
|
||||
|
||||
/*
|
||||
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | EnumDecl
|
||||
ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
|
||||
*/
|
||||
static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
|
||||
VisibMod visib_mod;
|
||||
|
||||
if (first_token->id == TokenIdKeywordPub) {
|
||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
||||
if (next_token->id == TokenIdPercentDot) {
|
||||
visib_mod = VisibModPub;
|
||||
*token_index += 2;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, next_token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (first_token->id == TokenIdKeywordExport) {
|
||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
||||
if (next_token->id == TokenIdPercentDot) {
|
||||
visib_mod = VisibModExport;
|
||||
*token_index += 2;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, next_token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (first_token->id == TokenIdPercentDot) {
|
||||
visib_mod = VisibModPrivate;
|
||||
*token_index += 1;
|
||||
} else if (mandatory) {
|
||||
ast_invalid_token_error(pc, first_token);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
|
||||
node->data.error_value_decl.visib_mod = visib_mod;
|
||||
ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
|
||||
*/
|
||||
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
|
||||
for (;;) {
|
||||
@ -2887,6 +3014,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, false);
|
||||
if (error_value_node) {
|
||||
top_level_decls->append(error_value_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
zig_unreachable();
|
||||
|
||||
@ -584,6 +584,11 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '.':
|
||||
t.cur_tok->id = TokenIdPercentDot;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -1092,6 +1097,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdDoubleQuestion: return "??";
|
||||
case TokenIdMaybeAssign: return "?=";
|
||||
case TokenIdAtSign: return "@";
|
||||
case TokenIdPercentDot: return "%.";
|
||||
}
|
||||
return "(invalid token)";
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ enum TokenId {
|
||||
TokenIdDoubleQuestion,
|
||||
TokenIdMaybeAssign,
|
||||
TokenIdAtSign,
|
||||
TokenIdPercentDot,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
||||
166
std/std.zig
166
std/std.zig
@ -1,43 +1,177 @@
|
||||
import "syscall.zig";
|
||||
//import "errno.zig";
|
||||
|
||||
pub const stdin_fileno : isize = 0;
|
||||
pub const stdout_fileno : isize = 1;
|
||||
pub const stderr_fileno : isize = 2;
|
||||
|
||||
// TODO error handling
|
||||
pub fn os_get_random_bytes(buf: []u8) isize => {
|
||||
getrandom(buf.ptr, buf.len, 0)
|
||||
/*
|
||||
pub var stdin = InStream {
|
||||
.fd = stdin_fileno,
|
||||
};
|
||||
|
||||
pub var stdout = OutStream {
|
||||
.fd = stdout_fileno,
|
||||
.buffer = uninitialized,
|
||||
.index = 0,
|
||||
.buffered = true,
|
||||
};
|
||||
|
||||
pub var stderr = OutStream {
|
||||
.fd = stderr_fileno,
|
||||
.buffer = uninitialized,
|
||||
.index = 0,
|
||||
.buffered = false,
|
||||
};
|
||||
|
||||
pub %.Unexpected;
|
||||
pub %.DiskQuota;
|
||||
pub %.FileTooBig;
|
||||
pub %.SigInterrupt;
|
||||
pub %.Io;
|
||||
pub %.NoSpaceLeft;
|
||||
pub %.BadPerm;
|
||||
pub %.PipeFail;
|
||||
*/
|
||||
|
||||
const buffer_size: u16 = 4 * 1024;
|
||||
const max_u64_base10_digits: isize = 20;
|
||||
|
||||
/*
|
||||
pub struct OutStream {
|
||||
fd: isize,
|
||||
buffer: [buffer_size]u8,
|
||||
index: @typeof(buffer_size),
|
||||
buffered: bool,
|
||||
|
||||
pub fn print_str(os: &OutStream, str: []const u8) %isize => {
|
||||
var src_bytes_left = str.len;
|
||||
var src_index: @typeof(str.len) = 0;
|
||||
const dest_space_left = os.buffer.len - index;
|
||||
|
||||
while (src_bytes_left > 0) {
|
||||
const copy_amt = min_isize(dest_space_left, src_bytes_left);
|
||||
@memcpy(&buffer[os.index], &str[src_index], copy_amt);
|
||||
os.index += copy_amt;
|
||||
if (os.index == os.buffer.len) {
|
||||
%return os.flush();
|
||||
}
|
||||
src_bytes_left -= copy_amt;
|
||||
}
|
||||
if (!os.buffered) {
|
||||
%return os.flush();
|
||||
}
|
||||
return str.len;
|
||||
}
|
||||
|
||||
pub fn print_u64(os: &OutStream, x: u64) %isize => {
|
||||
if (os.index + max_u64_base10_digits >= os.buffer.len) {
|
||||
%return os.flush();
|
||||
}
|
||||
const amt_printed = buf_print_u64(buf[os.index...], x);
|
||||
os.index += amt_printed;
|
||||
|
||||
if (!os.buffered) {
|
||||
%return os.flush();
|
||||
}
|
||||
|
||||
return amt_printed;
|
||||
}
|
||||
|
||||
|
||||
pub fn print_i64(os: &OutStream, x: i64) %isize => {
|
||||
if (os.index + max_u64_base10_digits >= os.buffer.len) {
|
||||
%return os.flush();
|
||||
}
|
||||
const amt_printed = buf_print_i64(buf[os.index...], x);
|
||||
os.index += amt_printed;
|
||||
|
||||
if (!os.buffered) {
|
||||
%return os.flush();
|
||||
}
|
||||
|
||||
return amt_printed;
|
||||
}
|
||||
|
||||
|
||||
pub fn flush(os: &OutStream) %void => {
|
||||
const amt_to_write = os.index;
|
||||
os.index = 0;
|
||||
switch (write(fd, os.buffer.ptr, amt_to_write)) {
|
||||
EINVAL => unreachable{},
|
||||
EDQUOT => %.DiskQuota,
|
||||
EFBIG => %.FileTooBig,
|
||||
EINTR => %.SigInterrupt,
|
||||
EIO => %.Io,
|
||||
ENOSPC => %.NoSpaceLeft,
|
||||
EPERM => %.BadPerm,
|
||||
EPIPE => %.PipeFail,
|
||||
else => %.Unexpected,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
pub struct InStream {
|
||||
fd: isize,
|
||||
|
||||
pub fn readline(buf: []u8) %isize => {
|
||||
const amt_read = read(stdin_fileno, buf.ptr, buf.len);
|
||||
if (amt_read < 0) {
|
||||
switch (-amt_read) {
|
||||
EINVAL => unreachable{},
|
||||
EFAULT => unreachable{},
|
||||
EBADF => %.BadFd,
|
||||
EINTR => %.SigInterrupt,
|
||||
EIO => %.Io,
|
||||
else => %.Unexpected,
|
||||
}
|
||||
}
|
||||
return amt_read;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn os_get_random_bytes(buf: []u8) %void => {
|
||||
switch (getrandom(buf.ptr, buf.len, 0)) {
|
||||
EINVAL => unreachable{},
|
||||
EFAULT => unreachable{},
|
||||
EINTR => %.SigInterrupt,
|
||||
else => %.Unexpected,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// TODO remove this
|
||||
pub fn print_str(str: []const u8) isize => {
|
||||
fprint_str(stdout_fileno, str)
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
// TODO remove this
|
||||
pub fn fprint_str(fd: isize, str: []const u8) isize => {
|
||||
write(fd, str.ptr, str.len)
|
||||
}
|
||||
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
// TODO error handling
|
||||
// TODO remove this
|
||||
pub fn os_get_random_bytes(buf: []u8) isize => {
|
||||
getrandom(buf.ptr, buf.len, 0)
|
||||
}
|
||||
|
||||
// TODO remove this
|
||||
pub fn print_u64(x: u64) isize => {
|
||||
var buf: [max_u64_base10_digits]u8;
|
||||
const len = buf_print_u64(buf, x);
|
||||
return write(stdout_fileno, buf.ptr, len);
|
||||
}
|
||||
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
// TODO error handling
|
||||
// TODO remove this
|
||||
pub fn print_i64(x: i64) isize => {
|
||||
var buf: [max_u64_base10_digits]u8;
|
||||
const len = buf_print_i64(buf, x);
|
||||
return write(stdout_fileno, buf.ptr, len);
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO remove this
|
||||
pub fn readline(buf: []u8, out_len: &isize) bool => {
|
||||
const amt_read = read(stdin_fileno, buf.ptr, buf.len);
|
||||
if (amt_read < 0) {
|
||||
@ -47,7 +181,8 @@ pub fn readline(buf: []u8, out_len: &isize) bool => {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO return ?u64 when we support returning struct byval
|
||||
|
||||
// TODO return %u64 when we support errors
|
||||
pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
|
||||
var x : u64 = 0;
|
||||
|
||||
@ -74,6 +209,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
|
||||
}
|
||||
|
||||
fn char_to_digit(c: u8) u8 => {
|
||||
// TODO use switch with range
|
||||
if ('0' <= c && c <= '9') {
|
||||
c - '0'
|
||||
} else if ('A' <= c && c <= 'Z') {
|
||||
@ -85,8 +221,6 @@ fn char_to_digit(c: u8) u8 => {
|
||||
}
|
||||
}
|
||||
|
||||
const max_u64_base10_digits: isize = 20;
|
||||
|
||||
fn buf_print_i64(out_buf: []u8, x: i64) isize => {
|
||||
if (x < 0) {
|
||||
out_buf[0] = '-';
|
||||
@ -112,7 +246,7 @@ fn buf_print_u64(out_buf: []u8, x: u64) isize => {
|
||||
|
||||
const len = buf.len - index;
|
||||
|
||||
@memcpy(out_buf.ptr, &buf[index], len);
|
||||
@memcpy(&out_buf[0], &buf[index], len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user