From c172188145a9f2c90abb9d53759689e7e62538d0 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Fri, 30 Aug 2024 11:28:07 +0200 Subject: [PATCH] feat: Type is now after identifiers Type variable -> var variable: Type closes #310 --- src/Parser.zig | 736 +++++++++++++++++------------------------ src/lib/buffer.buzz | 98 +++--- src/lib/crypto.buzz | 2 +- src/lib/debug.buzz | 4 +- src/lib/errors.buzz | 14 +- src/lib/ffi.buzz | 14 +- src/lib/fs.buzz | 10 +- src/lib/http.buzz | 50 ++- src/lib/io.buzz | 34 +- src/lib/math.buzz | 42 +-- src/lib/os.buzz | 42 +-- src/lib/serialize.buzz | 70 ++-- src/lib/std.buzz | 22 +- src/lib/testing.buzz | 112 +++---- 14 files changed, 563 insertions(+), 687 deletions(-) diff --git a/src/Parser.zig b/src/Parser.zig index 7968ff88..8ea6e0cd 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -856,48 +856,28 @@ pub fn parse(self: *Self, source: []const u8, file_name: []const u8) !?Ast { try self.advancePastEof(); while (!(try self.match(.Eof))) { - if (function_type == .Repl) { - // When running in REPL, global scope is allowed to run statements since the global scope becomes procedural - if (self.declarationOrStatement(null) catch |err| { - if (BuildOptions.debug) { - io.print("Parsing failed with error {}\n", .{err}); - } - return null; - }) |decl| { - var statements = std.ArrayList(Ast.Node.Index).fromOwnedSlice( - self.gc.allocator, - @constCast(self.ast.nodes.items(.components)[body_node].Block), - ); - defer statements.shrinkAndFree(statements.items.len); - - try statements.append(decl); - - self.ast.nodes.items(.components)[body_node].Block = statements.items; + if (self.declarationOrStatement(null) catch |err| { + if (function_type != .Repl and err == error.ReachedMaximumMemoryUsage) { + return err; } - } else { - if (self.declaration() catch |err| { - if (err == error.ReachedMaximumMemoryUsage) { - return err; - } - if (BuildOptions.debug) { - io.print("Parsing failed with error {}\n", .{err}); - } - return null; - }) |decl| { - var statements = std.ArrayList(Ast.Node.Index).fromOwnedSlice( - self.gc.allocator, - @constCast(self.ast.nodes.items(.components)[body_node].Block), - ); - defer statements.shrinkAndFree(statements.items.len); + if (BuildOptions.debug) { + io.print("Parsing failed with error {}\n", .{err}); + } + return null; + }) |decl| { + var statements = std.ArrayList(Ast.Node.Index).fromOwnedSlice( + self.gc.allocator, + @constCast(self.ast.nodes.items(.components)[body_node].Block), + ); + defer statements.shrinkAndFree(statements.items.len); - try statements.append(decl); + try statements.append(decl); - self.ast.nodes.items(.components)[body_node].Block = statements.items; - } else { - self.reportError(.syntax, "Expected statement"); - break; - } + self.ast.nodes.items(.components)[body_node].Block = statements.items; + } else { + self.reportError(.syntax, "Expected statement"); + break; } } @@ -1252,6 +1232,21 @@ fn simpleType(self: *Self, def_type: obj.ObjTypeDef.Type) Error!Ast.Node.Index { ); } +fn simpleTypeFromToken(token: Token.Type) ?obj.ObjTypeDef.Type { + return switch (token) { + .Pat => .Pattern, + .Ud => .UserData, + .Str => .String, + .Int => .Integer, + .Float => .Float, + .Bool => .Bool, + .Range => .Range, + .Type => .Type, + .Any => .Any, + else => null, + }; +} + fn declaration(self: *Self) Error!?Ast.Node.Index { const global_scope = self.current.?.scope_depth == 0; @@ -1260,291 +1255,197 @@ fn declaration(self: *Self) Error!?Ast.Node.Index { else null; - if (try self.match(.Extern)) { - const node = try self.funDeclaration(); - - self.ast.nodes.items(.docblock)[node] = docblock; + const node = if (try self.match(.Object)) + try self.objectDeclaration() + else if (try self.match(.Protocol)) + try self.protocolDeclaration() + else if (try self.match(.Enum)) + try self.enumDeclaration() + else if ((try self.match(.Fun)) or (global_scope and try self.match(.Extern))) + try self.funDeclaration() + else if ((try self.match(.Const)) or (try self.match(.Var))) variable: { + const constant = self.current_token.? > 0 and self.ast.tokens.items(.tag)[self.current_token.? - 1] == .Const; + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; - return node; - } else if ((self.current_token == 0 or self.ast.tokens.items(.tag)[self.current_token.? - 1] != .Export) and try self.match(.Export)) { - return try self.exportStatement(); - } else { - const constant: bool = try self.match(.Const); - - var node = if (global_scope and !constant and try self.match(.Object)) - try self.objectDeclaration() - else if (global_scope and !constant and try self.match(.Protocol)) - try self.protocolDeclaration() - else if (global_scope and !constant and try self.match(.Enum)) - try self.enumDeclaration() - else if (!constant and try self.match(.Fun)) - try self.funDeclaration() - else if (!constant and try self.match(.Var)) - try self.varDeclaration( - false, + // Type omitted? + if (!(try self.match(.DoubleColon))) { + break :variable try self.varDeclaration( + identifier, null, .Semicolon, - false, - true, - false, - ) - else if (try self.match(.Pat)) - try self.varDeclaration( - false, - try self.simpleType(.Pattern), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Ud)) - try self.varDeclaration( - false, - try self.simpleType(.UserData), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Str)) - try self.varDeclaration( - false, - try self.simpleType(.String), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Int)) - try self.varDeclaration( - false, - try self.simpleType(.Integer), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Float)) - try self.varDeclaration( - false, - try self.simpleType(.Float), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Bool)) - try self.varDeclaration( - false, - try self.simpleType(.Bool), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Range)) - try self.varDeclaration( - false, - try self.simpleType(.Range), - .Semicolon, - constant, - true, - false, - ) - else if (try self.match(.Type)) - try self.varDeclaration( - false, - try self.simpleType(.Type), - .Semicolon, constant, true, false, - ) - else if (try self.match(.Any)) - try self.varDeclaration( - false, - try self.simpleType(.Any), + ); + } + + // Simple types + for ([_]Token.Type{ .Pat, .Ud, .Str, .Int, .Float, .Bool, .Range, .Type, .Any }) |token| { + if (try self.match(token)) { + break :variable try self.varDeclaration( + identifier, + try self.simpleType(simpleTypeFromToken(token).?), + .Semicolon, + constant, + true, + false, + ); + } + } + + // Complex types + if (try self.match(.Fib)) + break :variable try self.varDeclaration( + identifier, + try self.parseFiberType(null), .Semicolon, constant, true, false, ) - else if (self.current_token.? > 0 and self.current_token.? - 1 < self.ast.tokens.len - 1 and - self.ast.tokens.items(.tag)[self.current_token.?] == .Identifier and - self.ast.tokens.items(.lexeme)[self.current_token.?].len == 1 and - self.ast.tokens.items(.lexeme)[self.current_token.?][0] == '_') - try self.varDeclaration( - false, - try self.simpleType(.Any), + else if (try self.match(.Obj)) + break :variable try self.varDeclaration( + identifier, + try self.parseObjType(null), .Semicolon, constant, true, false, ) - else if (try self.match(.Fib)) - try self.varDeclaration( - false, - try self.parseFiberType(null), + else if (try self.match(.LeftBracket)) + break :variable try self.varDeclaration( + identifier, + try self.parseListType(null), .Semicolon, constant, true, false, ) - else if (try self.match(.Obj)) - try self.varDeclaration( - false, - try self.parseObjType(null), + else if (try self.match(.LeftBrace)) + break :variable try self.varDeclaration( + identifier, + try self.parseMapType(null), .Semicolon, constant, true, false, ) - else if (try self.match(.LeftBracket)) - try self.listDeclaration(constant) - else if (try self.match(.LeftBrace)) - try self.mapDeclaration(constant) - else if (!constant and try self.match(.Test)) - try self.testStatement() else if (try self.match(.Function)) - try self.varDeclaration( - false, + break :variable try self.varDeclaration( + identifier, try self.parseFunctionType(null), .Semicolon, constant, true, false, ) - else if (global_scope and try self.match(.Import)) - try self.importStatement() - else if (global_scope and try self.match(.Zdef)) - try self.zdefStatement() - else if (global_scope and !constant and try self.match(.Export)) - try self.exportStatement() - else if (self.check(.Identifier)) user_decl: { - if ( // As of now this is the only place where we need to check more than one token ahead - // Note that we would not have to do this if type were given **after** the identifier. But changing this is a pretty big left turn. - // `Type variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Identifier }, 2) or - // `prefix.Type variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Identifier }, 4) or - // `prefix.Type? variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Question, .Identifier }, 5) or - // `Type? variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Question, .Identifier }, 3) or - // `Type::<...> variable` - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .DoubleColon, .Less, null, .Greater, .Identifier }, 255 * 2) or - // - Type::<...>? variable - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .DoubleColon, .Less, null, .Greater, .Question, .Identifier }, 255 * 2) or - // - prefix.Type::<...> variable - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .DoubleColon, .Less, null, .Greater, .Identifier }, 255 * 2) or - // - prefix.Type::<...>? variable - try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .DoubleColon, .Less, null, .Greater, .Question, .Identifier }, 255 * 2)) - { - _ = try self.advance(); // consume first identifier - break :user_decl try self.userVarDeclaration(false, constant); - } - - break :user_decl null; - } else if (global_scope and !constant and try self.match(.Export)) - try self.exportStatement() - else if (global_scope and !constant and try self.match(.Namespace)) - try self.namespaceStatement() - else - null; - - if (node == null and constant) { - node = try self.varDeclaration( - false, - null, - .Semicolon, - true, - true, - false, - ); + else if (try self.match(.Identifier)) { + _ = try self.advance(); // consume first identifier + break :variable try self.userVarDeclaration(identifier, constant); } - if (node != null and docblock != null) { - if (self.ast.nodes.items(.tag)[node.?] == .FunDeclaration) { - const components = self.ast.nodes.items(.components); - components[components[node.?].FunDeclaration.function].Function.docblock = docblock; - } - self.ast.nodes.items(.docblock)[node.?] = docblock; - } + break :variable null; + } else null; - if (self.reporter.panic_mode) { - try self.synchronize(); + if (node != null and docblock != null) { + if (self.ast.nodes.items(.tag)[node.?] == .FunDeclaration) { + const components = self.ast.nodes.items(.components); + components[components[node.?].FunDeclaration.function].Function.docblock = docblock; } + self.ast.nodes.items(.docblock)[node.?] = docblock; + } - return node; + if (self.reporter.panic_mode) { + try self.synchronize(); } + + return node; } + fn declarationOrStatement(self: *Self, loop_scope: ?LoopScope) !?Ast.Node.Index { return try self.declaration() orelse try self.statement(false, loop_scope); } // When a break statement, will return index of jump to patch fn statement(self: *Self, hanging: bool, loop_scope: ?LoopScope) !?Ast.Node.Index { - if (try self.match(.If)) { - std.debug.assert(!hanging); - return try self.ifStatement(loop_scope); - } else if (try self.match(.For)) { - std.debug.assert(!hanging); - return try self.forStatement(); - } else if (try self.match(.ForEach)) { - std.debug.assert(!hanging); - return try self.forEachStatement(); - } else if (try self.match(.While)) { - std.debug.assert(!hanging); - return try self.whileStatement(); - } else if (try self.match(.Do)) { - std.debug.assert(!hanging); - return try self.doUntilStatement(); - } else if (try self.match(.Return)) { - std.debug.assert(!hanging); - return try self.returnStatement(); - } else if (try self.match(.Try)) { - std.debug.assert(!hanging); - return try self.tryStatement(); - } else if (try self.match(.Break)) { - std.debug.assert(!hanging); - return try self.breakStatement(loop_scope); - } else if (try self.match(.Continue)) { - std.debug.assert(!hanging); - return try self.continueStatement(loop_scope); - } else if (try self.match(.Import)) { - std.debug.assert(!hanging); - return try self.importStatement(); - } else if (try self.match(.Out)) { - std.debug.assert(!hanging); - return try self.outStatement(); - } else if (try self.match(.Namespace)) { - std.debug.assert(!hanging); - return try self.namespaceStatement(); - } else if (try self.match(.Throw)) { - const start_location = self.current_token.? - 1; - // For now we don't care about the type. Later if we have `Error` type of data, we'll type check this - const error_value = try self.expression(false); + const global_scope = self.current.?.scope_depth == 0; + const statement_allowed = self.flavor == .Repl or !global_scope; - try self.consume(.Semicolon, "Expected `;` after statement."); + if (statement_allowed) { + if (try self.match(.If)) { + std.debug.assert(!hanging); + return try self.ifStatement(loop_scope); + } else if (try self.match(.For)) { + std.debug.assert(!hanging); + return try self.forStatement(); + } else if (try self.match(.ForEach)) { + std.debug.assert(!hanging); + return try self.forEachStatement(); + } else if (try self.match(.While)) { + std.debug.assert(!hanging); + return try self.whileStatement(); + } else if (try self.match(.Do)) { + std.debug.assert(!hanging); + return try self.doUntilStatement(); + } else if (!global_scope and try self.match(.Return)) { + std.debug.assert(!hanging); + return try self.returnStatement(); + } else if (try self.match(.Try)) { + std.debug.assert(!hanging); + return try self.tryStatement(); + } else if (!global_scope and try self.match(.Break)) { + std.debug.assert(!hanging); + return try self.breakStatement(loop_scope); + } else if (!global_scope and try self.match(.Continue)) { + std.debug.assert(!hanging); + return try self.continueStatement(loop_scope); + } else if (try self.match(.Out)) { + std.debug.assert(!hanging); + return try self.outStatement(); + } else if (try self.match(.Throw)) { + const start_location = self.current_token.? - 1; + // For now we don't care about the type. Later if we have `Error` type of data, we'll type check this + const error_value = try self.expression(false); - return try self.ast.appendNode( - .{ - .tag = .Throw, - .location = start_location, - .end_location = self.current_token.? - 1, - .components = .{ - .Throw = .{ - .expression = error_value, - .unconditional = self.current.?.scope_depth == 1, + try self.consume(.Semicolon, "Expected `;` after statement."); + + return try self.ast.appendNode( + .{ + .tag = .Throw, + .location = start_location, + .end_location = self.current_token.? - 1, + .components = .{ + .Throw = .{ + .expression = error_value, + .unconditional = self.current.?.scope_depth == 1, + }, }, }, - }, - ); - } else { - return try self.expressionStatement(hanging); + ); + } } - return null; + if (global_scope) { + if (try self.match(.Import)) { + std.debug.assert(!hanging); + return try self.importStatement(); + } else if (try self.match(.Namespace)) { + std.debug.assert(!hanging); + return try self.namespaceStatement(); + } else if (try self.match(.Test)) { + std.debug.assert(!hanging); + return try self.testStatement(); + } else if (try self.match(.Zdef)) { + std.debug.assert(!hanging); + return try self.zdefStatement(); + } else if (try self.match(.Export)) { + std.debug.assert(!hanging); + return try self.exportStatement(); + } + } + + return try self.expressionStatement(hanging); } fn addLocal(self: *Self, name: Ast.TokenIndex, local_type: *obj.ObjTypeDef, constant: bool) Error!usize { @@ -2165,8 +2066,7 @@ fn resolveUpvalue(self: *Self, frame: *Frame, name: Ast.TokenIndex) Error!?usize return null; } -fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast.TokenIndex, constant: bool, check_name: bool) Error!usize { - const name = name_token orelse self.current_token.? - 1; +fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name: Ast.TokenIndex, constant: bool, check_name: bool) Error!usize { const name_lexeme = self.ast.tokens.items(.lexeme)[name]; if (self.current.?.scope_depth > 0) { @@ -2242,18 +2142,18 @@ fn declareVariable(self: *Self, variable_type: *obj.ObjTypeDef, name_token: ?Ast fn parseVariable( self: *Self, - identifier_consumed: bool, + identifier: ?Ast.TokenIndex, variable_type: *obj.ObjTypeDef, constant: bool, error_message: []const u8, ) !usize { - if (!identifier_consumed) { + if (identifier == null) { try self.consume(.Identifier, error_message); } return try self.declareVariable( variable_type, - null, + identifier orelse self.current_token.? - 1, constant, true, ); @@ -2847,21 +2747,23 @@ fn parseFunctionType(self: *Self, parent_generic_types: ?std.AutoArrayHashMap(*o if (!self.check(.RightParen)) { while (true) { arity += 1; - if (arity > 255) { + if (arity > std.math.maxInt(u8)) { self.reportErrorAtCurrent(.arguments_count, "Can't have more than 255 arguments."); } + try self.consume(.Identifier, "Expected argument name"); + + const arg_name_token = self.current_token.? - 1; + const arg_name = self.ast.tokens.items(.lexeme)[self.current_token.? - 1]; + + try self.consume(.DoubleColon, "Expected `:`"); + const arg_type = try self.parseTypeDef( merged_generic_types, true, ); const arg_type_def = self.ast.nodes.items(.type_def)[arg_type]; - try self.consume(.Identifier, "Expected argument name"); - - const arg_name_token = self.current_token.? - 1; - const arg_name = self.ast.tokens.items(.lexeme)[self.current_token.? - 1]; - var default: ?Ast.Node.Index = null; if (try self.match(.Equal)) { const expr = try self.expression(false); @@ -4863,8 +4765,9 @@ fn @"if"(self: *Self, is_statement: bool, loop_scope: ?LoopScope) Error!Ast.Node var unwrapped_identifier: ?Ast.TokenIndex = null; var casted_type: ?Ast.Node.Index = null; if (try self.match(.Arrow)) { // if (opt -> unwrapped) + try self.consume(.Identifier, "Expected identifier"); _ = try self.parseVariable( - false, + self.current_token.? - 1, try condition_type_def.?.cloneNonOptional(&self.gc.type_registry), true, "Expected optional unwrap identifier", @@ -4875,8 +4778,9 @@ fn @"if"(self: *Self, is_statement: bool, loop_scope: ?LoopScope) Error!Ast.Node } else if (try self.match(.As)) { // if (expr as casted) casted_type = try self.parseTypeDef(null, true); + try self.consume(.Identifier, "Expected identifier"); _ = try self.parseVariable( - false, + self.current_token.? - 1, try self.ast.nodes.items(.type_def)[casted_type.?].?.toInstance(self.gc.allocator, &self.gc.type_registry), true, "Expected casted identifier", @@ -5259,13 +5163,17 @@ fn function( if (!self.check(.RightParen)) { while (true) { arity += 1; - if (arity > 255) { + if (arity > std.math.maxInt(u8)) { self.reportErrorAtCurrent( .arguments_count, "Can't have more than 255 arguments.", ); } + try self.consume(.Identifier, "Expected argument name"); + const identifier = self.current_token.? - 1; + try self.consume(.DoubleColon, "Expected `:`"); + const argument_type_node = try self.parseTypeDef( function_typedef.resolved_type.?.Function.generic_types, true, @@ -5281,7 +5189,7 @@ fn function( const argument_type = self.ast.nodes.items(.type_def)[argument_type_node].?; const slot = try self.parseVariable( - false, + identifier, argument_type, true, // function arguments are constant "Expected argument name", @@ -6445,13 +6353,15 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index { try properties_type.put(method_name, self.ast.nodes.items(.type_def)[method_node].?); } else { const constant = try self.match(.Const); - const property_type = try self.parseTypeDef(null, true); - const property_type_def = self.ast.nodes.items(.type_def)[property_type]; try self.consume(.Identifier, "Expected property name."); const property_token = self.current_token.? - 1; const property_name = self.ast.tokens.get(property_token); + try self.consume(.DoubleColon, "Expected `:`"); + const property_type = try self.parseTypeDef(null, true); + const property_type_def = self.ast.nodes.items(.type_def)[property_type]; + if (fields.get(property_name.lexeme) != null) { self.reportError(.property_already_exists, "A member with that name already exists."); } @@ -6944,7 +6854,7 @@ fn enumDeclaration(self: *Self) Error!Ast.Node.Index { fn varDeclaration( self: *Self, - identifier_consumed: bool, + identifier: ?Ast.TokenIndex, parsed_type: ?Ast.Node.Index, terminator: DeclarationTerminator, constant: bool, @@ -6960,7 +6870,7 @@ fn varDeclaration( self.gc.type_registry.any_type; const slot: usize = try self.parseVariable( - identifier_consumed, + identifier, var_type, constant, "Expected variable name.", @@ -7077,42 +6987,6 @@ fn implicitVarDeclaration(self: *Self, name: Ast.TokenIndex, parsed_type: *obj.O ); } -fn listDeclaration(self: *Self, constant: bool) Error!Ast.Node.Index { - const current_function_type = self.ast.nodes.items(.type_def)[self.current.?.function_node].?.resolved_type.?.Function.function_type; - - if (self.check(.Less) and (self.current.?.scope_depth > 0 or current_function_type == .Repl)) { - // Its a list expression - return try self.expressionStatement(true); - } - - return try self.varDeclaration( - false, - try self.parseListType(null), - .Semicolon, - constant, - true, - false, - ); -} - -fn mapDeclaration(self: *Self, constant: bool) Error!Ast.Node.Index { - const current_function_type = self.ast.nodes.items(.type_def)[self.current.?.function_node].?.resolved_type.?.Function.function_type; - - if (self.check(.Less) and (self.current.?.scope_depth > 0 or current_function_type == .Repl)) { - // Its a map expression - return try self.expressionStatement(true); - } - - return try self.varDeclaration( - false, - try self.parseMapType(null), - .Semicolon, - constant, - true, - false, - ); -} - // `test` is just like a function but we don't parse arguments and we don't care about its return type fn testStatement(self: *Self) Error!Ast.Node.Index { const start_location = self.current_token.? - 1; @@ -7966,129 +7840,125 @@ fn zdefStatement(self: *Self) Error!Ast.Node.Index { } // FIXME: this is almost the same as parseUserType! -fn userVarDeclaration(self: *Self, _: bool, constant: bool) Error!Ast.Node.Index { +fn userVarDeclaration(self: *Self, identifier: Ast.TokenIndex, constant: bool) Error!Ast.Node.Index { const start_location = self.current_token.? - 1; - const identifier = self.current_token.? - 1; var var_type: ?*obj.ObjTypeDef = null; - const inferred_declaration = self.check(.Equal) and constant; var generic_resolve: ?Ast.Node.Index = null; // If next token is `=`, means the identifier wasn't a user type but the variable name // and the type needs to be inferred - if (!inferred_declaration) { - const user_type_name = self.current_token.? - 1; + const user_type_name = self.current_token.? - 1; - // Is it a generic type defined in enclosing functions or object? - if (self.resolveGeneric(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { + // Is it a generic type defined in enclosing functions or object? + if (self.resolveGeneric(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { + var_type = generic_type; + } else if (self.current.?.generics != null) { + // Is it generic type defined in a function signature being parsed? + if (self.current.?.generics.?.get(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { var_type = generic_type; - } else if (self.current.?.generics != null) { - // Is it generic type defined in a function signature being parsed? - if (self.current.?.generics.?.get(try self.gc.copyString(self.ast.tokens.items(.lexeme)[self.current_token.? - 1]))) |generic_type| { - var_type = generic_type; - } } + } - // Search for a global with that name - if (var_type == null) { - if (try self.resolveGlobal(null, self.ast.tokens.items(.lexeme)[user_type_name])) |slot| { - const global = self.globals.items[slot]; + // Search for a global with that name + if (var_type == null) { + if (try self.resolveGlobal(null, self.ast.tokens.items(.lexeme)[user_type_name])) |slot| { + const global = self.globals.items[slot]; - var_type = global.type_def; + var_type = global.type_def; - if (global.imported_from != null and self.script_imports.get(global.imported_from.?) != null) { - const imported_from = global.imported_from.?; + if (global.imported_from != null and self.script_imports.get(global.imported_from.?) != null) { + const imported_from = global.imported_from.?; - try self.script_imports.put( - imported_from, - .{ - .location = self.script_imports.get(imported_from).?.location, - .referenced = true, - }, - ); - } + try self.script_imports.put( + imported_from, + .{ + .location = self.script_imports.get(imported_from).?.location, + .referenced = true, + }, + ); } } + } - // If none found, create a placeholder - if (var_type == null) { - var_type = try self.gc.type_registry.getTypeDef( - .{ - .def_type = .Placeholder, - .resolved_type = .{ - // TODO: token is wrong but what else can we put here? - .Placeholder = obj.PlaceholderDef.init(self.gc.allocator, user_type_name), - }, + // If none found, create a placeholder + if (var_type == null) { + var_type = try self.gc.type_registry.getTypeDef( + .{ + .def_type = .Placeholder, + .resolved_type = .{ + // TODO: token is wrong but what else can we put here? + .Placeholder = obj.PlaceholderDef.init(self.gc.allocator, user_type_name), }, - ); + }, + ); - _ = try self.declarePlaceholder(user_type_name, var_type); - } + _ = try self.declarePlaceholder(user_type_name, var_type); + } - // Concrete generic types list - generic_resolve = if (try self.match(.DoubleColon)) gn: { - const generic_start = self.current_token.? - 1; + // Concrete generic types list + generic_resolve = if (try self.match(.DoubleColon)) gn: { + const generic_start = self.current_token.? - 1; - try self.consume(.Less, "Expected generic types list after `::`"); + try self.consume(.Less, "Expected generic types list after `::`"); - var resolved_generics = std.ArrayList(*obj.ObjTypeDef).init(self.gc.allocator); - defer resolved_generics.shrinkAndFree(resolved_generics.items.len); - var generic_nodes = std.ArrayList(Ast.Node.Index).init(self.gc.allocator); - defer generic_nodes.shrinkAndFree(generic_nodes.items.len); - var i: usize = 0; - while (!self.check(.Greater) and !self.check(.Eof)) : (i += 1) { - try generic_nodes.append( - try self.parseTypeDef( - if (self.current.?.generics) |generics| - generics.* - else - null, - true, - ), - ); + var resolved_generics = std.ArrayList(*obj.ObjTypeDef).init(self.gc.allocator); + defer resolved_generics.shrinkAndFree(resolved_generics.items.len); + var generic_nodes = std.ArrayList(Ast.Node.Index).init(self.gc.allocator); + defer generic_nodes.shrinkAndFree(generic_nodes.items.len); + var i: usize = 0; + while (!self.check(.Greater) and !self.check(.Eof)) : (i += 1) { + try generic_nodes.append( + try self.parseTypeDef( + if (self.current.?.generics) |generics| + generics.* + else + null, + true, + ), + ); - try resolved_generics.append( - self.ast.nodes.items(.type_def)[generic_nodes.items[generic_nodes.items.len - 1]].?, - ); + try resolved_generics.append( + self.ast.nodes.items(.type_def)[generic_nodes.items[generic_nodes.items.len - 1]].?, + ); - if (!self.check(.Greater)) { - try self.consume(.Comma, "Expected `,` between generic types"); - } + if (!self.check(.Greater)) { + try self.consume(.Comma, "Expected `,` between generic types"); } + } - try self.consume(.Greater, "Expected `>` after generic types list"); + try self.consume(.Greater, "Expected `>` after generic types list"); - if (resolved_generics.items.len == 0) { - self.reportErrorAtCurrent(.generic_type, "Expected at least one type"); - } + if (resolved_generics.items.len == 0) { + self.reportErrorAtCurrent(.generic_type, "Expected at least one type"); + } - // Shouldn't we populate only in codegen? - var_type = try var_type.?.populateGenerics( - self.current_token.? - 1, - var_type.?.resolved_type.?.Object.id, - resolved_generics.items, - &self.gc.type_registry, - null, - ); + // Shouldn't we populate only in codegen? + var_type = try var_type.?.populateGenerics( + self.current_token.? - 1, + var_type.?.resolved_type.?.Object.id, + resolved_generics.items, + &self.gc.type_registry, + null, + ); - break :gn try self.ast.appendNode( - .{ - .tag = .GenericResolveType, - .location = generic_start, - .end_location = self.current_token.? - 1, - .type_def = var_type, - .components = .{ - .GenericResolveType = .{ - .resolved_types = generic_nodes.items, - }, + break :gn try self.ast.appendNode( + .{ + .tag = .GenericResolveType, + .location = generic_start, + .end_location = self.current_token.? - 1, + .type_def = var_type, + .components = .{ + .GenericResolveType = .{ + .resolved_types = generic_nodes.items, }, }, - ); - } else null; + }, + ); + } else null; - if (try self.match(.Question)) { - var_type = try var_type.?.cloneOptional(&self.gc.type_registry); - } + if (try self.match(.Question)) { + var_type = try var_type.?.cloneOptional(&self.gc.type_registry); } const user_type_node = try self.ast.appendNode( @@ -8107,7 +7977,7 @@ fn userVarDeclaration(self: *Self, _: bool, constant: bool) Error!Ast.Node.Index ); return try self.varDeclaration( - inferred_declaration, + identifier, user_type_node, .Semicolon, constant, @@ -8127,13 +7997,16 @@ fn forStatement(self: *Self) Error!Ast.Node.Index { var init_declarations = std.ArrayList(Ast.Node.Index).init(self.gc.allocator); defer init_declarations.shrinkAndFree(init_declarations.items.len); while (!self.check(.Semicolon) and !self.check(.Eof)) { + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; + try init_declarations.append( try self.varDeclaration( - false, - if (try self.match(.Var)) - null + identifier, + if (try self.match(.DoubleColon)) + try self.parseTypeDef(null, true) else - try self.parseTypeDef(null, true), + null, .Nothing, false, true, @@ -8215,9 +8088,11 @@ fn forEachStatement(self: *Self) Error!Ast.Node.Index { try self.beginScope(null); - const infer_key_type = try self.match(.Var); + try self.consume(.Identifier, "Expected identifier"); + const key_identifier = self.current_token.? - 1; + const infer_key_type = try self.match(.DoubleColon); var key = try self.varDeclaration( - false, + key_identifier, if (infer_key_type) null else @@ -8229,10 +8104,13 @@ fn forEachStatement(self: *Self) Error!Ast.Node.Index { ); const key_omitted = !(try self.match(.Comma)); - const infer_value_type = !key_omitted and try self.match(.Var); + try self.consume(.Var, "Expected `var`"); + try self.consume(.Identifier, "Expected identifier"); + const value_identifier = self.current_token.? - 1; + const infer_value_type = !key_omitted and try self.match(.DoubleColon); var value = if (!key_omitted) try self.varDeclaration( - false, + value_identifier, if (infer_value_type) null else @@ -8585,16 +8463,18 @@ fn tryStatement(self: *Self) Error!Ast.Node.Index { try self.beginScope(null); + try self.consume(.Identifier, "Expected identifier"); + const identifier = self.current_token.? - 1; + try self.consume(.DoubleColon, "Expected `:`"); const type_def = try self.parseTypeDef(null, true); _ = try self.parseVariable( - false, + identifier, self.ast.nodes.items(.type_def)[type_def].?, true, // function arguments are constant "Expected error identifier", ); - const identifier = self.current_token.? - 1; self.markInitialized(); try self.consume(.RightParen, "Expected `)` after error identifier"); diff --git a/src/lib/buffer.buzz b/src/lib/buffer.buzz index 7221479f..d6cbc942 100644 --- a/src/lib/buffer.buzz +++ b/src/lib/buffer.buzz @@ -8,74 +8,74 @@ export object OutOfBoundError {} || @private extern fun BufferNew(int capacity) > ud; || @private -extern fun BufferDeinit(ud userdata) > void; +extern fun BufferDeinit(userdata: ud) > void; || @private -extern fun BufferRead(ud userdata, int n) > str?; +extern fun BufferRead(userdata: ud, int n) > str?; || @private -extern fun BufferWrite(ud userdata, str bytes) > void !> WriteWhileReadingError; +extern fun BufferWrite(userdata: ud, bytes: str) > void !> WriteWhileReadingError; || @private -extern fun BufferReadBoolean(ud userdata) > bool?; +extern fun BufferReadBoolean(userdata: ud) > bool?; || @private -extern fun BufferWriteBoolean(ud userdata, bool b) > void !> WriteWhileReadingError; +extern fun BufferWriteBoolean(userdata: ud, b: bool) > void !> WriteWhileReadingError; || @private -extern fun BufferWriteInt(ud userdata, int n) > void !> WriteWhileReadingError; +extern fun BufferWriteInt(userdata: ud, n: int) > void !> WriteWhileReadingError; || @private -extern fun BufferReadInt(ud userdata) > int?; +extern fun BufferReadInt(userdata: ud) > int?; || @private -extern fun BufferWriteUserData(ud userdata, ud ptr) > void !> WriteWhileReadingError; +extern fun BufferWriteUserData(userdata: ud, ptr: ud) > void !> WriteWhileReadingError; || @private -extern fun BufferReadUserData(ud userdata) > ud?; +extern fun BufferReadUserData(userdata: ud) > ud?; || @private -extern fun BufferWriteFloat(ud userdata, float n) > void !> WriteWhileReadingError; +extern fun BufferWriteFloat(userdata: ud, n: float) > void !> WriteWhileReadingError; || @private -extern fun BufferReadFloat(ud userdata) > float?; +extern fun BufferReadFloat(userdata: ud) > float?; || @private -extern fun BufferLen(ud userdata, int align) > int; +extern fun BufferLen(userdata: ud, align: int) > int; || @private -extern fun BufferCursor(ud userdata) > int; +extern fun BufferCursor(userdata: ud) > int; || @private -extern fun BufferBuffer(ud userdata) > str; +extern fun BufferBuffer(userdata: ud) > str; || @private -extern fun BufferPtr(ud userdata, int at, int alignment) > ud; +extern fun BufferPtr(userdata: ud, at: int, alignment: int) > ud; || @private -extern fun BufferEmpty(ud userdata) > void; +extern fun BufferEmpty(userdata: ud) > void; || @private -extern fun BufferAt(ud userdata, int index) > int; +extern fun BufferAt(userdata: ud, index: int) > int; || @private -extern fun BufferSetAt(ud userdata, int index, int value) > void; +extern fun BufferSetAt(userdata: ud, index: int, value:int ) > void; || @private -extern fun BufferWriteZ(ud userdata, str zigType, [any] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; +extern fun BufferWriteZ(userdata: ud, zigType: str, values: [any]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; || @private -extern fun BufferWriteZAt(ud userdata, int at, str zigType, [any] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; +extern fun BufferWriteZAt(userdata: ud, at: int, zigType: str, values: [any]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; || @private -extern fun BufferReadZ::(ud userdata, str zigType) > T !> ffi.FFITypeMismatchError; +extern fun BufferReadZ::(userdata: ud, zigType: str) > T !> ffi.FFITypeMismatchError; || @private -extern fun BufferReadZAt::(ud userdata, int at, str zigType) > T !> ffi.FFITypeMismatchError; +extern fun BufferReadZAt::(userdata: ud, at: int, zigType: str) > T !> ffi.FFITypeMismatchError; || @private -extern fun BufferWriteStruct::(ud userdata, type structType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; +extern fun BufferWriteStruct::(userdata: ud, structType: type, values: [T]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; || @private -extern fun BufferWriteStructAt::(ud userdata, type structType, int at, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; +extern fun BufferWriteStructAt::(userdata: ud, structType: type, at: int, values: [T]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError; || @private -extern fun BufferReadStruct::(ud userdata, type structType) > T !> ffi.FFITypeMismatchError; +extern fun BufferReadStruct::(userdata: ud, structType: type) > T !> ffi.FFITypeMismatchError; || @private -extern fun BufferReadStructAt::(ud userdata, type structType, int at) > T !> ffi.FFITypeMismatchError; +extern fun BufferReadStructAt::(userdata: ud, structType: type, at: int) > T !> ffi.FFITypeMismatchError; || Read and write data to a string buffer export object Buffer { || @private - ud buffer, + buffer: ud, || @private - bool released = false, + released: bool = false, || @return A new `Buffer` - static fun init(int capacity = 0) > Buffer { + static fun init(capacity: int = 0) > Buffer { return Buffer{ buffer = BufferNew(capacity) }; } - static fun fromStr(str string) > Buffer { - Buffer buffer = Buffer.init(); + static fun fromStr(string: str) > Buffer { + const buffer = Buffer.init(); | We're sure we did not read this buffer before buffer.write(string) catch void; @@ -94,45 +94,45 @@ export object Buffer { || Reads `n` bytes || @return Read bytes or `null` if nothing to read - fun read(int n = 1) > str? { + fun read(n: int = 1) > str? { return BufferRead(this.buffer, n: n); } || Writes a string || @param bytes Bytes to write - fun write(str bytes) > void !> WriteWhileReadingError { + fun write(bytes: str) > void !> WriteWhileReadingError { BufferWrite(this.buffer, bytes: bytes); } - fun writeZ::(str zigType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeZ::(zigType: str, values: [T]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { BufferWriteZ(this.buffer, zigType: zigType, values: values); } - fun writeZAt::(int at, str zigType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeZAt::(at: int, zigType: str, values: [T]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { BufferWriteZAt(this.buffer, at: at, zigType: zigType, values: values); } - fun readZ::(str zigType) > T !> ffi.FFITypeMismatchError { + fun readZ::(zigType: str) > T !> ffi.FFITypeMismatchError { return BufferReadZ::(this.buffer, zigType: zigType); } - fun readZAt::(int at, str zigType) > T !> ffi.FFITypeMismatchError { + fun readZAt::(at: int, zigType: str) > T !> ffi.FFITypeMismatchError { return BufferReadZAt::(this.buffer, at: at, zigType: zigType); } - fun writeStruct::(type structType, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeStruct::(structType: type, values: [T]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { BufferWriteStruct::(this.buffer, structType: structType, values: values); } - fun writeStructAt::(type structType, int at, [T] values) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { + fun writeStructAt::(structType: type, at: int, values: [T]) > void !> WriteWhileReadingError, ffi.FFITypeMismatchError { BufferWriteStructAt::(this.buffer, structType: structType, at: at, values: values); } - fun readStruct::(type structType) > T !> ffi.FFITypeMismatchError { + fun readStruct::(structType: type) > T !> ffi.FFITypeMismatchError { return BufferReadStruct::(this.buffer, structType: structType); } - fun readStructAt::(type structType, int at) > T !> ffi.FFITypeMismatchError { + fun readStructAt::(structType: type, at: int) > T !> ffi.FFITypeMismatchError { return BufferReadStructAt::(this.buffer, structType: structType, at: at); } @@ -144,7 +144,7 @@ export object Buffer { || Writes a boolean || @param boolean Boolean to write - fun writeBoolean(bool boolean) > void !> WriteWhileReadingError { + fun writeBoolean(boolean: bool) > void !> WriteWhileReadingError { BufferWriteBoolean(this.buffer, b: boolean); } @@ -156,7 +156,7 @@ export object Buffer { || Writes an integer || @param number Integer to write - fun writeInt(int number) > void !> WriteWhileReadingError { + fun writeInt(number: int) > void !> WriteWhileReadingError { BufferWriteInt(this.buffer, n: number); } @@ -168,7 +168,7 @@ export object Buffer { || Writes an ud || @param number UserDataeger to write - fun writeUserData(ud userdata) > void !> WriteWhileReadingError { + fun writeUserData(userdata: ud) > void !> WriteWhileReadingError { BufferWriteUserData(this.buffer, ptr: userdata); } @@ -180,13 +180,13 @@ export object Buffer { || Writes a float || @param number Float to write - fun writeFloat(float number) > void !> WriteWhileReadingError { + fun writeFloat(number: float) > void !> WriteWhileReadingError { BufferWriteFloat(this.buffer, n: number); } || @return Length of the buffer - fun len(int align = 1) > int { + fun len(align: int = 1) > int { return BufferLen(this.buffer, align: align); } @@ -206,12 +206,12 @@ export object Buffer { } || Get buffer's ptr - fun ptr(int at = 0, int align = 1) > ud { + fun ptr(at: int = 0, int align = 1) > ud { return BufferPtr(this.buffer, at: at, alignment: align); } || Get byte at `index` - fun at(int index) > int !> OutOfBoundError { + fun at(index: int) > int !> OutOfBoundError { if (index < this.len()) { return BufferAt(this.buffer, index: index); } @@ -220,7 +220,7 @@ export object Buffer { } || Set byte at `index` - fun setAt(int index, int value) > void !> WriteWhileReadingError, OutOfBoundError { + fun setAt(index: int, value: int) > void !> WriteWhileReadingError, OutOfBoundError { if (index < this.len()) { BufferSetAt(this.buffer, index: index, value: value); diff --git a/src/lib/crypto.buzz b/src/lib/crypto.buzz index 494f07c1..d044bb78 100644 --- a/src/lib/crypto.buzz +++ b/src/lib/crypto.buzz @@ -21,4 +21,4 @@ export enum HashAlgorithm { || @param algo Hash algorithm to use || @param data Data to hash || @return Hash of data has hex string -export extern fun hash(HashAlgorithm algo, str data) > str; +export extern fun hash(algo: HashAlgorithm, data: str) > str; diff --git a/src/lib/debug.buzz b/src/lib/debug.buzz index 1dcaf2c0..94f7304c 100644 --- a/src/lib/debug.buzz +++ b/src/lib/debug.buzz @@ -1,11 +1,11 @@ namespace debug; || Dump any value to stdout -export extern fun dump(any value) > void; +export extern fun dump(value: any) > void; | Parse `source` and return the abstract syntax tree in JSON | @param source the buzz source | @param script name (used to fetch eventual extern functions) | @return AST as JSON | TODO: reactivate -| export extern fun ast(str source, str scriptName) > str !> CompileError; \ No newline at end of file +| export extern fun ast(source: str, scriptName: str) > str !> CompileError; diff --git a/src/lib/errors.buzz b/src/lib/errors.buzz index 460500a7..f1873ff7 100644 --- a/src/lib/errors.buzz +++ b/src/lib/errors.buzz @@ -110,23 +110,23 @@ export enum ReadWriteError { } export object CompileError { - str message = "CompileError", + message: str = "CompileError", } export object InterpretError { - str message = "InterpretError", + message: str = "InterpretError", } export object InvalidArgumentError { - str message = "InvalidArgumentError", + message: str = "InvalidArgumentError", } export object NotYetImplementedError { - str message = "NotYetImplementedError", + message: str = "NotYetImplementedError", } export object OverflowError { - str message = "OverflowError", + message: str = "OverflowError", } export object UnderflowError { - str message = "UnderflowError", + message: str = "UnderflowError", } export object UnexpectedError { - str message = "UnexpectedError", + message: str = "UnexpectedError", } diff --git a/src/lib/ffi.buzz b/src/lib/ffi.buzz index 53a9b0b0..8a4c15ea 100644 --- a/src/lib/ffi.buzz +++ b/src/lib/ffi.buzz @@ -1,19 +1,19 @@ namespace ffi; -export fun cstr(str string) => "{string}\0"; +export fun cstr(string: str) => "{string}\0"; export object FFITypeMismatchError { - str message = "Provided buzz value type does not match expected FFI type", + message: str = "Provided buzz value type does not match expected FFI type", } export object FFIZigTypeParseError { - str message = "Could not parse zig type", + message: str = "Could not parse zig type", } -export extern fun alignOf(str zigType) > int; +export extern fun alignOf(zigType: str) > int; -export extern fun sizeOf(str zigType) > int; +export extern fun sizeOf(zigType: str) > int; -export extern fun sizeOfStruct(type structType) > int; +export extern fun sizeOfStruct(structType: type) > int; -export extern fun alignOfStruct(type structType) > int; \ No newline at end of file +export extern fun alignOfStruct(structType: type) > int; diff --git a/src/lib/fs.buzz b/src/lib/fs.buzz index 06295db4..4d26e79d 100644 --- a/src/lib/fs.buzz +++ b/src/lib/fs.buzz @@ -18,22 +18,22 @@ export fun currentDirectory() > str !> errors.FileSystemError, errors.InvalidArg || Creates directory path || @param path directory to create -export extern fun makeDirectory(str path) > void !> errors.FileSystemError, errors.UnexpectedError; +export extern fun makeDirectory(path: str) > void !> errors.FileSystemError, errors.UnexpectedError; || Deletes directory or file at path || @param path direcotry/file to delete -export extern fun delete(str path) > void !> errors.FileSystemError, errors.UnexpectedError; +export extern fun delete(path: str) > void !> errors.FileSystemError, errors.UnexpectedError; || Moves/renames file || @param source file to move || @param destination where to move it -export extern fun move(str source, str destination) > void !> errors.FileSystemError, errors.UnexpectedError; +export extern fun move(source: str, destination: str) > void !> errors.FileSystemError, errors.UnexpectedError; || List files under path || @param path directory to list -export extern fun list(str path) > [str] !> errors.FileSystemError, errors.UnexpectedError; +export extern fun list(path: str) > [str] !> errors.FileSystemError, errors.UnexpectedError; || Returns true if path exists || @param path directory/file to test || @return wether file exists -export extern fun exists(str path) > bool !> errors.FileSystemError; \ No newline at end of file +export extern fun exists(path: str) > bool !> errors.FileSystemError; diff --git a/src/lib/http.buzz b/src/lib/http.buzz index f6e7b44b..360b175d 100644 --- a/src/lib/http.buzz +++ b/src/lib/http.buzz @@ -66,15 +66,15 @@ export enum(str) Method { || @private extern fun HttpClientNew() > ud; || @private -extern fun HttpClientDeinit(ud client) > void; +extern fun HttpClientDeinit(client: ud) > void; || @private -extern fun HttpClientSend(ud client, Method method, str uri, {str: str} headers) > ud !> HttpError; +extern fun HttpClientSend(client: ud, method: Method, uri: str, headers: {str: str}) > ud !> HttpError; || @private -extern fun HttpRequestWait(ud request) > void !> HttpError; +extern fun HttpRequestWait(request: ud) > void !> HttpError; || @private -extern fun HttpRequestRead(ud request) > Response !> HttpError; +extern fun HttpRequestRead(request: ud) > Response !> HttpError; || @private -extern fun HttpRequestDeinit(ud request) > void; +extern fun HttpRequestDeinit(request: ud) > void; const {int: str} reasons = { 100: "Continue", @@ -147,19 +147,19 @@ const {int: str} reasons = { }; export object HttpParseError{ - str? message = null, + message: str? = null, } object Connection { || @private - ud connection, + connection: ud, } export object Client { || @private - ud client, + client: ud, || @private - bool collected = false, + collected: bool = false, static fun init() > Client { return Client{ @@ -167,7 +167,7 @@ export object Client { }; } - fun send(Request request) > Response *> void !> HttpError, errors.InvalidArgumentError, HttpParseError { + fun send(request: Request) > Response *> void !> HttpError, errors.InvalidArgumentError, HttpParseError { _ = this.start(request); yield void; @@ -175,7 +175,7 @@ export object Client { return request.wait(); } - fun start(Request request) > Request !> HttpError { + fun start(request: Request) > Request !> HttpError { if (this.collected) { throw HttpError.ClientCollected; } @@ -204,13 +204,13 @@ export object Client { } export object Request { - ud? request = null, - Response? response = null, - Method method, - {str: str} headers = {}, - str uri = "/", - str? body = null, - bool collected = false, + request: ud? = null, + response: Response? = null, + method: Method, + headers: {str: str} = {}, + uri: str = "/", + body: str? = null, + collected: bool = false, fun wait() > Response !> HttpError, errors.InvalidArgumentError, HttpParseError { if (this.collected) { @@ -251,9 +251,7 @@ export object Request { result.write("{this.body ?? ""}\r\n"); - str strResult = result.toString(); - - return strResult; + return result.toString(); } catch {} return ""; @@ -262,9 +260,9 @@ export object Request { | Don't change proeprties order export object Response { - int status = 200, - {str: str} headers = {}, - str? body = null, + status: int = 200, + headers: {str: str} = {}, + body: str? = null, fun toString() > str { try { @@ -277,9 +275,7 @@ export object Response { result.write("\r\n{this.body ?? ""}\r\n"); - str strResult = result.toString(); - - return strResult; + return result.toString(); } catch {} return "HTTP/1.1 500 Internal Server Error"; diff --git a/src/lib/io.buzz b/src/lib/io.buzz index 135de88e..180fc225 100644 --- a/src/lib/io.buzz +++ b/src/lib/io.buzz @@ -3,17 +3,17 @@ namespace io; import "errors"; || @private -extern fun FileOpen(str filename, int mode) > int !> errors.FileSystemError, errors.UnexpectedError; +extern fun FileOpen(filename: str, mode: int) > int !> errors.FileSystemError, errors.UnexpectedError; || @private -extern fun FileClose(int fd) > void; +extern fun FileClose(fd: int) > void; || @private -extern fun FileReadAll(int fd, int? maxSize) > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError; +extern fun FileReadAll(fd: int, maxSize: int?) > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError; || @private -extern fun FileReadLine(int fd, int? maxSize) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError; +extern fun FileReadLine(fd: int, maxSize: int?) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError; || @private -extern fun FileRead(int fd, int n) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.InvalidArgumentError, errors.UnexpectedError; +extern fun FileRead(fd: int, n: int) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.InvalidArgumentError, errors.UnexpectedError; || @private -extern fun FileWrite(int fd, str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; +extern fun FileWrite(fd: int, bytes: str) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; || @private extern fun getStdIn() > int; || @private @@ -21,7 +21,7 @@ extern fun getStdOut() > int; || @private extern fun getStdErr() > int; || @private -extern fun FileIsTTY(int fd) > bool; +extern fun FileIsTTY(fd: int) > bool; || File mode with which you can open a file export enum FileMode { @@ -33,13 +33,13 @@ export enum FileMode { || Object to manipulate an opened file export object File { || File descriptor - int fd, + fd: int, || Open file || @param filename Path of file to open || @param mode Mode with which to open it || @return opened file - static fun open(str filename, FileMode mode) > File !> errors.FileSystemError, errors.UnexpectedError { + static fun open(filename: str, mode: FileMode) > File !> errors.FileSystemError, errors.UnexpectedError { return File { fd = FileOpen(filename, mode: mode.value), }; @@ -56,26 +56,26 @@ export object File { || Reads file until `EOF` || @return Read data - fun readAll(int? maxSize) > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { + fun readAll(maxSize: int?) > str !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { return FileReadAll(this.fd, maxSize); } || Reads next line, returns null if nothing to read || @return Read data - fun readLine(int? maxSize) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { + fun readLine(maxSize: int?) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.UnexpectedError { return FileReadLine(this.fd, maxSize); } || Reads `n` bytes, returns null if nothing to read || @param n how many bytes to read || @return Read data - fun read(int n) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.InvalidArgumentError, errors.UnexpectedError { + fun read(n: int) > str? !> errors.ReadWriteError, errors.FileSystemError, errors.InvalidArgumentError, errors.UnexpectedError { return FileRead(this.fd, n: n); } || Write bytes || @param bytes string to write - fun write(str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { + fun write(bytes: str) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { FileWrite(this.fd, bytes: bytes); } @@ -86,12 +86,12 @@ export object File { } || stdin -export const File stdin = File{ fd = getStdIn() }; +export const stdin = File{ fd = getStdIn() }; || stdout -export const File stdout = File{ fd = getStdOut() }; +export const stdout = File{ fd = getStdOut() }; || stderr -export const File stderr = File{ fd = getStdErr() }; +export const stderr = File{ fd = getStdErr() }; || Run a buzz file || @param filename path to buzz file -export extern fun runFile(str filename) > void !> errors.CompileError, errors.InterpretError, errors.FileSystemError, errors.ReadWriteError; \ No newline at end of file +export extern fun runFile(filename: str) > void !> errors.CompileError, errors.InterpretError, errors.FileSystemError, errors.ReadWriteError; diff --git a/src/lib/math.buzz b/src/lib/math.buzz index e4ba2370..43af0a68 100644 --- a/src/lib/math.buzz +++ b/src/lib/math.buzz @@ -3,68 +3,68 @@ namespace math; import "errors"; || @return absolute value of n -extern fun abs(float n) > float; +extern fun abs(n: float) > float; || @return acos of n -extern fun acos(float n) > float; +extern fun acos(n: float) > float; || @return asin of n -extern fun asin(float n) > float; +extern fun asin(n: float) > float; || @return atan of n -extern fun atan(float n) > float; +extern fun atan(n: float) > float; || @return ceiled n -extern fun bzceil(float n) > int; +extern fun bzceil(n: float) > int; || @return cos of n -extern fun bzcos(float n) > float; +extern fun bzcos(n: float) > float; || π constant -const float pi = 3.1415926535898; +const pi: float = 3.1415926535898; || Convert radian to degree -fun deg(float n) > float { +fun deg(n: float) > float { return n * 180.0 / pi; } || @return exp of n -extern fun bzexp(float n) > float; +extern fun bzexp(n: float) > float; || @returned floored n -extern fun bzfloor(float n) > int; +extern fun bzfloor(n: float) > int; || @return log(base) of n -extern fun bzlog(float base, float n) > float; +extern fun bzlog(base: float, n: float) > float; || @return max of a and b -extern fun maxFloat(float a, float b) > float; +extern fun maxFloat(a: float, b: float) > float; || @return min of a and b -extern fun minFloat(float a, float b) > float; +extern fun minFloat(a: float, b: float) > float; || @return max of a and b -extern fun maxInt(int a, int b) > int; +extern fun maxInt(a: int, b: int) > int; || @return min of a and b -extern fun minInt(int a, int b) > int; +extern fun minInt(a: int, b: int) > int; || Convert degree to radian -fun rad(float n) > float { +fun rad(n: float) > float { return n * pi / 180.0; } || @return sin of n -extern fun bzsin(float n) > float; +extern fun bzsin(n: float) > float; || @return square root of n -extern fun bzsqrt(float n) > float; +extern fun bzsqrt(n: float) > float; || @return tan of n -extern fun bztan(float n) > float; +extern fun bztan(n: float) > float; || @return `x`^`y` -extern fun pow(float x, float y) > float !> errors.OverflowError, errors.UnderflowError; +extern fun pow(x: float, y: float) > float !> errors.OverflowError, errors.UnderflowError; export abs; export acos; @@ -85,4 +85,4 @@ export pi; export rad; export bzsin as sin; export bztan as tan; -export pow; \ No newline at end of file +export pow; diff --git a/src/lib/os.buzz b/src/lib/os.buzz index ee01fea1..d809c0c7 100644 --- a/src/lib/os.buzz +++ b/src/lib/os.buzz @@ -3,49 +3,49 @@ namespace os; import "errors"; || Sleep for the given amount of ms -export extern fun sleep(float ms) > void; +export extern fun sleep(ms: float) > void; || @return epoch time in ms export extern fun time() > float; || Returns environment variable under `key` || @param key environment variable name -export extern fun env(str key) > str?; +export extern fun env(key: str) > str?; || @return path to system temp directory export extern fun tmpDir() > str; || @param prefix prefix to the temp file name || @return a temporary file name in system tmp dir -export extern fun tmpFilename(str? prefix) > str; +export extern fun tmpFilename(prefix: str?) > str; || Exit program with `exitCode` || @param exitCode exit code -extern fun buzzExit(int exitCode) > void; +extern fun buzzExit(exitCode: int) > void; export buzzExit as exit; || Execute command and return its exit code || @param command command to execute || @return exit code of the command -export extern fun execute([str] command) > int !> errors.FileSystemError, errors.UnexpectedError; +export extern fun execute(command: [str]) > int !> errors.FileSystemError, errors.UnexpectedError; || @private -extern fun SocketConnect(str address, int port, int netProtocol) > int !> errors.InvalidArgumentError, errors.SocketError, errors.NotYetImplementedError; +extern fun SocketConnect(address: str, port: int, netProtocol: int) > int !> errors.InvalidArgumentError, errors.SocketError, errors.NotYetImplementedError; || @private -extern fun SocketClose(int fd) > void; +extern fun SocketClose(fd: int) > void; || @private -extern fun SocketRead(int fd, int n) > str? !> errors.InvalidArgumentError, errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; +extern fun SocketRead(fd: int, n: int) > str? !> errors.InvalidArgumentError, errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; || @private -extern fun SocketWrite(int fd, str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; +extern fun SocketWrite(fd: int, bytes: str) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError; || @private -extern fun SocketServerStart(str address, int port, bool reuseAddr, bool reusePort) > int !> errors.InvalidArgumentError, errors.SocketError, errors.UnexpectedError, errors.FileSystemError; +extern fun SocketServerStart(address: str, port: int, reuseAddr: bool, reusePort: bool) > int !> errors.InvalidArgumentError, errors.SocketError, errors.UnexpectedError, errors.FileSystemError; || @private -extern fun SocketServerAccept(int fd) > int !> errors.SocketError, errors.UnexpectedError; +extern fun SocketServerAccept(fd: int) > int !> errors.SocketError, errors.UnexpectedError; || @private -extern fun SocketReadLine(int fd, int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError; +extern fun SocketReadLine(fd: int, maxSize: int?) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError; || @private -extern fun SocketReadAll(int fd, int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError; +extern fun SocketReadAll(fd: int, maxSize: int?) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError; || Protocols supported over a socket export enum SocketProtocol { @@ -57,14 +57,14 @@ export enum SocketProtocol { || A socket export object Socket { || @private - int fd, + fd: int, || Opens a socket || @param address A string containing either a IPv4, IPv6 or path to a socket file (IPC) || @param port Port to which to connect || @param protocol Protocol to use || @return A new `Socket` opened and ready to use - static fun connect(str address, int port = 0, SocketProtocol netProtocol) > Socket !> errors.InvalidArgumentError, errors.SocketError, errors.NotYetImplementedError { + static fun connect(address: str, port: int = 0, netProtocol: SocketProtocol) > Socket !> errors.InvalidArgumentError, errors.SocketError, errors.NotYetImplementedError { return Socket{ fd = SocketConnect(address, port: port, netProtocol: netProtocol.value), }; @@ -78,25 +78,25 @@ export object Socket { || Receive at most `n` bytes from the socket || @param n How many bytes we're prepare to receive || @return The bytes received or null if nothing to read - fun receive(int n) > str? !> errors.InvalidArgumentError, errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { + fun receive(n: int) > str? !> errors.InvalidArgumentError, errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { return SocketRead(this.fd, n: n); } || Receive from socket until it's closed or a linefeed is received || @return The bytes received or null if nothing to read - fun receiveLine(int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError { + fun receiveLine(maxSize: int?) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError { return SocketReadLine(this.fd, maxSize); } || Receive from socket until it's closed || @return The bytes received or null if nothing to read - fun receiveAll(int? maxSize) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError { + fun receiveAll(maxSize: int?) > str? !> errors.FileSystemError, errors.UnexpectedError, errors.ReadWriteError { return SocketReadAll(this.fd, maxSize); } || Send bytes on the socket || @param bytes Bytes to send - fun send(str bytes) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { + fun send(bytes: str) > void !> errors.FileSystemError, errors.ReadWriteError, errors.UnexpectedError { SocketWrite(this.fd, bytes: bytes); } } @@ -116,7 +116,7 @@ export object TcpServer { || @param reuseAddr Wether we want to accept multiple connections || @param reusePort Wether we want to accept multiple connections || @return New `TcpServer` bound to `
:` - static fun init(str address, int port, bool reuseAddr, bool reusePort) > TcpServer !> errors.SocketError, errors.UnexpectedError, errors.InvalidArgumentError, errors.FileSystemError { + static fun init(address: str, port: int, reuseAddr: bool, reusePort: bool) > TcpServer !> errors.SocketError, errors.UnexpectedError, errors.InvalidArgumentError, errors.FileSystemError { return TcpServer{ serverSocket = Socket{ fd = SocketServerStart(address, port: port, reuseAddr: reuseAddr, reusePort: reusePort), @@ -142,4 +142,4 @@ export object TcpServer { export SocketProtocol; export Socket; -export TcpServer; \ No newline at end of file +export TcpServer; diff --git a/src/lib/serialize.buzz b/src/lib/serialize.buzz index 478af85d..e26d3c00 100644 --- a/src/lib/serialize.buzz +++ b/src/lib/serialize.buzz @@ -5,9 +5,9 @@ import "std"; || Utility object to manage deserialized data from, for example, decoded JSON export object Boxed { - any data = null, + data: any = null, - static fun init(any data) > Boxed !> CircularReference, NotSerializable { + static fun init(data: any) > Boxed !> CircularReference, NotSerializable { return Boxed{ data = serializeValue(data), }; @@ -36,9 +36,9 @@ export object Boxed { || When wrapped data is an object, object property values are themselves wrapped in a `Boxed` fun map() > {str: Boxed}? { if (this.data as? {str: any} -> dataMap) { - {str: Boxed} boxedMap = {}; + var boxedMap = {}; - foreach (str key, any value in dataMap) { + foreach (key: str, value: any in dataMap) { boxedMap[key] = Boxed{ data = value }; } @@ -51,9 +51,9 @@ export object Boxed { || When wrapped data is a list, list elements are themselves warpped in a `Boxed` fun list() > [Boxed]? { if (this.data as? [any] -> dataList) { - [Boxed] boxedList = []; + var boxedList = []; - foreach (any element in dataList) { + foreach (element: any in dataList) { boxedList.append(Boxed{ data = element }); } @@ -79,7 +79,7 @@ export object Boxed { || Query the json element at `path`, if nothing matches return `Boxed{}` || @param path Path to query || @return Found `Boxed` or `Boxed{}` (which is `null`) - fun q([str] path) > Boxed { + fun q(path: [str]) > Boxed { if (this.map() -> map) { if (path.len() > 1) { return (map[path[0]] ?? Boxed{}).q(path.sub(1)); @@ -102,10 +102,10 @@ export object NotSerializable { str message = "Not serializable", } -export extern fun serializeValue(any value) > any !> CircularReference, NotSerializable; +export extern fun serializeValue(value: any) > any !> CircularReference, NotSerializable; export object JsonParseError { - str? message = null, + message: str? = null, } || Parse JSON string into a `Json` tree @@ -113,15 +113,15 @@ export object JsonParseError { object JsonParser { | TODO: comform to https://datatracker.ietf.org/doc/html/rfc8259 - str source, - int offset = 0, + source: str, + offset: int = 0, fun advance() > str? { if (this.offset >= this.source.len()) { return null; } - str char = this.source[this.offset]; + var char = this.source[this.offset]; this.offset = this.offset + 1; @@ -136,7 +136,7 @@ object JsonParser { return this.source[this.offset]; } - fun match(str expected) > bool { + fun match(expected: str) > bool { if (this.offset > this.source.len() or this.source[this.offset] != expected) { return false; } @@ -146,7 +146,7 @@ object JsonParser { return true; } - fun consume(str expected) > void !> JsonParseError { + fun consume(expected: str) > void !> JsonParseError { if (!this.match(expected)) { throw JsonParseError{ message = "Could not parse JSON: expected `{expected}` got `{this.peek()}` at offset {this.offset}" }; } @@ -154,7 +154,7 @@ object JsonParser { fun skipWhitespaces() > void { while (true) { - const str? char = this.peek(); + const char = this.peek(); if (char == " " or char == "\r" or char == "\t" or char == "\n") { _ = this.advance(); @@ -171,8 +171,8 @@ object JsonParser { throw JsonParseError{ message = "Could not parse JSON: end of string" }; } - const str char = this.advance() ?? ""; - const int byte = char.byte(0); + const char = this.advance() ?? ""; + const byte = char.byte(0); if (char == "[") { return this.array(); } else if (char == "\{") { @@ -196,7 +196,7 @@ object JsonParser { } fun array() > [any] !> JsonParseError, buffer.WriteWhileReadingError { - [any] array = []; + var array = []; while (true) { this.skipWhitespaces(); @@ -220,7 +220,7 @@ object JsonParser { } fun map() > {str: any} !> JsonParseError, buffer.WriteWhileReadingError { - {str: any} map = {}; + var map = {}; while (true) { this.skipWhitespaces(); @@ -230,7 +230,7 @@ object JsonParser { } this.consume("\""); - const str key = this.string(); + const key = this.string(); this.skipWhitespaces(); @@ -252,12 +252,12 @@ object JsonParser { return map; } - fun number(str parsed) > any !> JsonParseError { - str number = parsed; + fun number(parsed: str) > any !> JsonParseError { + var number = parsed; - bool isFloat = false; + var isFloat = false; while (std.parseInt(this.peek() ?? "NaN") != null or this.peek() == ".") { - str? char = this.advance(); + var char = this.advance(); if (char == null) { break; @@ -282,7 +282,7 @@ object JsonParser { } fun string() > str !> buffer.WriteWhileReadingError { - str? char = this.advance(); + var char = this.advance(); var string = buffer.Buffer.init(); while (char != null and char != "\"") { @@ -305,7 +305,7 @@ object JsonParser { char = this.advance(); } - str result = string.toString(); + var result = string.toString(); return result; } @@ -313,7 +313,7 @@ object JsonParser { || Encode to a JSON string || @return the JSON string -export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { +export fun jsonEncode(data: Boxed) > str !> CircularReference, NotSerializable { if (data.string() -> string) { return "\"{string}\""; } else if (data.boolean() -> boolean) { @@ -323,10 +323,10 @@ export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { } else if (data.floating() -> floating) { return "{floating}"; } else if (data.map() -> map) { - str json = "\{"; - const int size = map.size(); - int count = 0; - foreach (str key, Boxed value in map) { + var json = "\{"; + const size = map.size(); + var count = 0; + foreach (key: key, value: Boxed in map) { json = json + "\"{key}\":{jsonEncode(value)}"; if (count < size - 1) { @@ -339,8 +339,8 @@ export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { } else if (data.list() -> list) { str json = "["; - const int len = list.len(); - foreach (int i, Boxed value in list) { + const len = list.len(); + foreach (i: int, value: Boxed in list) { json = json + jsonEncode(value); if (i < len - 1) { @@ -357,10 +357,10 @@ export fun jsonEncode(Boxed data) > str !> CircularReference, NotSerializable { || Decode string into a Json instance || @param str json The JSON string || @return Boxed -export fun jsonDecode(str json) > Boxed !> JsonParseError, buffer.WriteWhileReadingError { +export fun jsonDecode(json: str) > Boxed !> JsonParseError, buffer.WriteWhileReadingError { return Boxed{ data = JsonParser{ source = json }.next() }; -} \ No newline at end of file +} diff --git a/src/lib/std.buzz b/src/lib/std.buzz index 2dd16f29..a04fa632 100644 --- a/src/lib/std.buzz +++ b/src/lib/std.buzz @@ -3,56 +3,56 @@ namespace std; || If condition is false print message and exit program || @param condition assert condition || @param message message printed if `condition` is false -export extern fun assert(bool condition, str? message = null) > void; +export extern fun assert(condition: bool, message: str? = null) > void; || Prints value on stdout || @param value value to print -export extern fun print(str value) > void; +export extern fun print(value: str) > void; || Parse integer, returns false if string does not represent a integer || @param string string to parse || @return integer parsed or null -export extern fun parseInt(str string) > int?; +export extern fun parseInt(string: str) > int?; || Parse float, returns false if string does not represent a float || @param string string to parse || @return float parsed or null -export extern fun parseFloat(str string) > float?; +export extern fun parseFloat(string: str) > float?; || Cast integer to a float value || @param n value to cast || @return casted value -export extern fun toInt(float n) > int; +export extern fun toInt(n: float) > int; || Cast float to a integer value || @param n value to cast || @return casted value -export extern fun toFloat(int n) > float; +export extern fun toFloat(n: int) > float; | FIXME: once we have type composition this might be more elegant || Cast float or integer to userdata || @param n value to cast || @return casted value or 0 if value provided is not a number -export extern fun toUd(any n) > ud; +export extern fun toUd(n: any) > ud; || Parse ud, returns false if string does not represent a ud (u64) || @param string string to parse || @return ud parsed or null -export extern fun parseUd(str string) > ud?; +export extern fun parseUd(string: str) > ud?; || Return ascii char for given byte -export extern fun char(int byte) > str; +export extern fun char(byte: int) > str; || Return evenly distributed random number between `min` and `max` || @param min Minimum value, if omitted `0` || @param max Maximum value, if omitted `min + 1` || @return Random value -export extern fun random(int? min = null, int? max = null) > int; +export extern fun random(min: int? = null, max: int? = null) > int; || @return Current fiber export extern fun currentFiber() > fib; || Print message and exit program -extern fun buzzPanic(str message) > void; +extern fun buzzPanic(message: str) > void; export buzzPanic as panic; diff --git a/src/lib/testing.buzz b/src/lib/testing.buzz index 5dc1e8b6..d938a0cc 100644 --- a/src/lib/testing.buzz +++ b/src/lib/testing.buzz @@ -34,47 +34,47 @@ export enum(int) Color { onwhite = 47, } -export fun color(str text, Color color, bool reset = true) > str { +export fun color(text: str, color: Color, reset: bool = true) > str { return "\27[{color.value}m{text}{if (reset) "\27[0m" else ""}"; } -export fun bright(str text) => color(text, color: Color.bright); -export fun dim(str text) => color(text, color: Color.dim); -export fun underscore(str text) => color(text, color: Color.underscore); -export fun blink(str text) => color(text, color: Color.blink); -export fun reverse(str text) => color(text, color: Color.reverse); -export fun hidden(str text) => color(text, color: Color.hidden); -export fun black(str text) => color(text, color: Color.black); -export fun red(str text) => color(text, color: Color.red); -export fun green(str text) => color(text, color: Color.green); -export fun yellow(str text) => color(text, color: Color.yellow); -export fun blue(str text) => color(text, color: Color.blue); -export fun magenta(str text) => color(text, color: Color.magenta); -export fun cyan(str text) => color(text, color: Color.cyan); -export fun white(str text) => color(text, color: Color.white); -export fun onblack(str text) => color(text, color: Color.onblack); -export fun onred(str text) => color(text, color: Color.onred); -export fun ongreen(str text) => color(text, color: Color.ongreen); -export fun onyellow(str text) => color(text, color: Color.onyellow); -export fun onblue(str text) => color(text, color: Color.onblue); -export fun onmagenta(str text) => color(text, color: Color.onmagenta); -export fun oncyan(str text) => color(text, color: Color.oncyan); -export fun onwhite(str text) => color(text, color: Color.onwhite); +export fun bright(text: str) => color(text, color: Color.bright); +export fun dim(text: str) => color(text, color: Color.dim); +export fun underscore(text: str) => color(text, color: Color.underscore); +export fun blink(text: str) => color(text, color: Color.blink); +export fun reverse(text: str) => color(text, color: Color.reverse); +export fun hidden(text: str) => color(text, color: Color.hidden); +export fun black(text: str) => color(text, color: Color.black); +export fun red(text: str) => color(text, color: Color.red); +export fun green(text: str) => color(text, color: Color.green); +export fun yellow(text: str) => color(text, color: Color.yellow); +export fun blue(text: str) => color(text, color: Color.blue); +export fun magenta(text: str) => color(text, color: Color.magenta); +export fun cyan(text: str) => color(text, color: Color.cyan); +export fun white(text: str) => color(text, color: Color.white); +export fun onblack(text: str) => color(text, color: Color.onblack); +export fun onred(text: str) => color(text, color: Color.onred); +export fun ongreen(text: str) => color(text, color: Color.ongreen); +export fun onyellow(text: str) => color(text, color: Color.onyellow); +export fun onblue(text: str) => color(text, color: Color.onblue); +export fun onmagenta(text: str) => color(text, color: Color.onmagenta); +export fun oncyan(text: str) => color(text, color: Color.oncyan); +export fun onwhite(text: str) => color(text, color: Color.onwhite); export object Tester { - [bool] tests = [], - [bool] asserts = [], - float elapsed = 0.0, - Function(Tester t) > void? beforeAll, - Function(Tester t) > void? beforeEach, - Function(Tester t) > void? afterAll, - Function(Tester t) > void? afterEach, + tests: [bool] = [], + asserts: [bool] = [], + elapsed: float = 0.0, + beforeAll: Function(Tester t) > void?, + beforeEach: Function(Tester t) > void?, + afterAll: Function(Tester t) > void?, + afterEach: Function(Tester t) > void?, static fun init( - Function(Tester t) > void? beforeAll, - Function(Tester t) > void? beforeEach, - Function(Tester t) > void? afterAll, - Function(Tester t) > void? afterEach + beforeAll: Function(Tester t) > void?, + beforeEach: Function(Tester t) > void?, + afterAll: Function(Tester t) > void?, + afterEach: Function(Tester t) > void? ) > Tester { var t = Tester{ beforeAll = beforeAll, @@ -98,7 +98,7 @@ export object Tester { fun failedAsserts() > int { return this.asserts.reduce::( - fun (int _, bool success, int accumulator) + fun (_: int, success: bool, accumulator: int) => accumulator + if (success) 0 else 1, initial: 0, ); @@ -106,7 +106,7 @@ export object Tester { fun failedTests() > int { return this.tests.reduce::( - fun (int _, bool success, int accumulator) + fun (_: int, success: bool, accumulator: int) => accumulator + if (success) 0 else 1, initial: 0, ); @@ -114,14 +114,14 @@ export object Tester { fun succeededTests() > int { return this.tests.reduce::( - fun (int _, bool success, int accumulator) + fun (_: int, success: bool, accumulator: int) => accumulator + if (success) 1 else 0, initial: 0, ); } - fun it(str message, Function() > void fn) > void { - float startTime = os.time(); + fun it(message: str, fn: Function() > void) > void { + var startTime = os.time(); io.stdout.write(yellow("▶ Test: {message}\n")) catch void; @@ -129,7 +129,7 @@ export object Tester { beforeEach(this); } - int previousFailCount = this.failedAsserts(); + var previousFailCount = this.failedAsserts(); fn(); if (this.afterEach -> afterEach) { @@ -150,7 +150,7 @@ export object Tester { io.stdout.write("\n") catch void; - foreach (bool testStatus in this.tests) { + foreach (testStatus: bool in this.tests) { if (testStatus) { io.stdout.write(green("●")) catch void; } else { @@ -172,11 +172,11 @@ export object Tester { } } - fun report(str? error, str? message) > void { + fun report(error: str?, message: str?) > void { io.stderr.write(red(" Assert failed: {message ?? ""}") + dim("\n {error}\n")) catch void; } - fun assert(bool condition, str? error, str? message) > void { + fun assert(condition: bool, error: str?, message: str?) > void { if (!condition) { this.report(error, message: message); @@ -186,7 +186,7 @@ export object Tester { } } - fun assertEqual::(T actual, T expected, str? message) > void { + fun assertEqual::(actual: T, expected: T, message: str?) > void { this.assert( actual == expected, error: "expected `{expected}` got `{actual}`", @@ -194,7 +194,7 @@ export object Tester { ); } - fun assertNotEqual::(T actual, T expected, str? message) > void { + fun assertNotEqual::(actual: T, expected: T, message: str?) > void { this.assert( actual != expected, error: "expected `{expected}` got `{actual}`", @@ -202,14 +202,14 @@ export object Tester { ); } - fun assertAreEqual::([T] values, str? message) > void { + fun assertAreEqual::(values: [T], message: str?) > void { if (values.len() < 2) { return; } - bool equal = true; - T previous = values[0]; - foreach (T value in values) { + var equal = true; + var previous = values[0]; + foreach (value: T in values) { if (value != previous) { equal = false; break; @@ -225,14 +225,14 @@ export object Tester { ); } - fun assertAreNotEqual::([T] values, str? message) > void { + fun assertAreNotEqual::(values: [T], message: str?) > void { if (values.len() < 2) { return; } - bool equal = true; - T previous = values[0]; - foreach (int i, T value in values) { + var equal = true; + var previous = values[0]; + foreach (i: int, value: T in values) { if (i > 0 and value == previous) { equal = false; break; @@ -248,7 +248,7 @@ export object Tester { ); } - fun assertOfType::(any value, str? message) > void { + fun assertOfType::(value: any, message: str?) > void { this.assert( !(value is T), error: "`{value}` type is `{typeof value}`", @@ -256,7 +256,7 @@ export object Tester { ); } - fun assertThrows::(Function() > void !> T fn, str? message) > void { + fun assertThrows::(Function() > void !> T fn, message: str?) > void { try { fn(); } catch (any error) { @@ -267,7 +267,7 @@ export object Tester { this.assert(false, error: "Did not throw", message: message); } - fun assertDoesNotThrow::(Function() > void fn, str? message) > void { + fun assertDoesNotThrow::(fn: Function() > void, message: str?) > void { try { fn(); } catch (any error) {