Compare commits
	
		
			No commits in common. "master" and "zig-bug-report" have entirely different histories.
		
	
	
		
			master
			...
			zig-bug-re
		
	
		
					 9 changed files with 144 additions and 219 deletions
				
			
		|  | @ -37,6 +37,7 @@ negatively charged towards | ||||||
| 
 | 
 | ||||||
| ## wip | ## wip | ||||||
| 
 | 
 | ||||||
|  |  - no `for` yet | ||||||
|  - no `map` yet |  - no `map` yet | ||||||
|  - no `in` yet (probably will be dropped) |  - no `in` yet (probably will be dropped) | ||||||
|  - no `module`, `import` yet |  - no `module`, `import` yet | ||||||
|  |  | ||||||
|  | @ -17,8 +17,6 @@ fn main(a int) int { | ||||||
| 	mut a := 1+2 | 	mut a := 1+2 | ||||||
| 	a = 2 | 	a = 2 | ||||||
| 
 | 
 | ||||||
| 	a = 1 && 0 |  | ||||||
| 
 |  | ||||||
| 	if a { | 	if a { | ||||||
| 		println(30) | 		println(30) | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -65,9 +63,6 @@ fn main(a int) int { | ||||||
| 	str.len /= 1 | 	str.len /= 1 | ||||||
| 
 | 
 | ||||||
| 	awoo := [1, 2, a(), b + 2, c(31) * d] | 	awoo := [1, 2, a(), b + 2, c(31) * d] | ||||||
| 
 |  | ||||||
| 	for a in b {} |  | ||||||
| 	for idx, a in b {} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (v Typ) voidfunc() {} | fn (v Typ) voidfunc() {} | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								src/ast.zig
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								src/ast.zig
									
										
									
									
									
								
							|  | @ -158,20 +158,12 @@ pub const LoopStmt = struct { | ||||||
|     then_branch: Block, |     then_branch: Block, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub const ForStmt = struct { |  | ||||||
|     index: ?Token, |  | ||||||
|     value: Token, |  | ||||||
|     array: Token, |  | ||||||
|     block: Block, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| pub const Stmt = union(enum) { | pub const Stmt = union(enum) { | ||||||
|     Expr: *Expr, |     Expr: *Expr, | ||||||
|     Println: *Expr, |     Println: *Expr, | ||||||
| 
 | 
 | ||||||
|     If: IfStmt, |     If: IfStmt, | ||||||
|     Loop: LoopStmt, |     Loop: LoopStmt, | ||||||
|     For: ForStmt, |  | ||||||
| 
 | 
 | ||||||
|     Return: ReturnStmt, |     Return: ReturnStmt, | ||||||
| 
 | 
 | ||||||
|  | @ -220,20 +212,6 @@ pub const Stmt = union(enum) { | ||||||
|         return stmt; |         return stmt; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn mkFor(allocator: *std.mem.Allocator, index: ?Token, value: Token, array: Token, block: Block) !*Stmt { |  | ||||||
|         var stmt = try allocator.create(Stmt); |  | ||||||
|         stmt.* = Stmt{ |  | ||||||
|             .For = ForStmt{ |  | ||||||
|                 .index = index, |  | ||||||
|                 .value = value, |  | ||||||
|                 .array = array, |  | ||||||
|                 .block = block, |  | ||||||
|             }, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         return stmt; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn mkReturn(allocator: *std.mem.Allocator, tok: Token, value: *Expr) !*Stmt { |     pub fn mkReturn(allocator: *std.mem.Allocator, tok: Token, value: *Expr) !*Stmt { | ||||||
|         var stmt = try allocator.create(Stmt); |         var stmt = try allocator.create(Stmt); | ||||||
|         stmt.* = Stmt{ |         stmt.* = Stmt{ | ||||||
|  |  | ||||||
|  | @ -9,28 +9,28 @@ const warn = std.debug.warn; | ||||||
| fn printIdent(ident: usize) void { | fn printIdent(ident: usize) void { | ||||||
|     var i: usize = 0; |     var i: usize = 0; | ||||||
|     while (i < ident) : (i += 1) { |     while (i < ident) : (i += 1) { | ||||||
|         std.debug.warn("\t", .{}); |         std.debug.warn("\t"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn print(ident: usize, comptime fmt: []const u8, args: anytype) void { | fn print(ident: usize, comptime fmt: []const u8, args: ...) void { | ||||||
|     printIdent(ident); |     printIdent(ident); | ||||||
|     std.debug.warn(fmt, args); |     std.debug.warn(fmt, args); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn printBlock(ident: usize, block: anytype, endNewline: bool) void { | fn printBlock(ident: usize, block: var, endNewline: bool) void { | ||||||
|     std.debug.warn("(\n", .{}); |     std.debug.warn("(\n"); | ||||||
| 
 | 
 | ||||||
|     for (block.items) |stmt| { |     for (block.toSlice()) |stmt| { | ||||||
|         printIdent(ident); |         printIdent(ident); | ||||||
|         printStmt(ident, stmt); |         printStmt(ident, stmt); | ||||||
|         std.debug.warn("\n", .{}); |         std.debug.warn("\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (endNewline) { |     if (endNewline) { | ||||||
|         print(ident - 1, ")\n", .{}); |         print(ident - 1, ")\n"); | ||||||
|     } else { |     } else { | ||||||
|         print(ident - 1, ")", .{}); |         print(ident - 1, ")"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -48,51 +48,55 @@ pub fn printNode(node: *Node, ident: usize) void { | ||||||
|                 const typ = method.typ.lexeme; |                 const typ = method.typ.lexeme; | ||||||
| 
 | 
 | ||||||
|                 if (method.mutable) { |                 if (method.mutable) { | ||||||
|                     warn("(method mut {} {} {} {} ", .{ vari, typ, name, ret_type }); |                     warn("(method mut {} {} {} {} ", vari, typ, name, ret_type); | ||||||
|                 } else { |                 } else { | ||||||
|                     warn("(method {} {} {} {} ", .{ vari, typ, name, ret_type }); |                     warn("(method {} {} {} {} ", vari, typ, name, ret_type); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 warn("(fn {} {} (", .{ name, ret_type }); |                 warn("(fn {} {} (", name, ret_type); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             for (decl.params.items) |param| { |             for (decl.params.toSlice()) |param| { | ||||||
|                 warn("({} {}) ", .{ param.name.lexeme, param.typ.lexeme }); |                 warn("({} {}) ", param.name.lexeme, param.typ.lexeme); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             printBlock(ident + 1, decl.body, false); |             printBlock(ident + 1, decl.body, false); | ||||||
|             warn(")\n", .{}); |             warn(")\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .ConstDecl => |consts| { |         .ConstDecl => |consts| { | ||||||
|             print(ident, "(const (\n", .{}); |             print(ident, "(const (\n"); | ||||||
| 
 | 
 | ||||||
|             for (consts.items) |const_decl| { |             for (consts.toSlice()) |const_decl| { | ||||||
|                 print(ident + 1, "({} ", .{ |                 print( | ||||||
|  |                     ident + 1, | ||||||
|  |                     "({} ", | ||||||
|                     const_decl.name.lexeme, |                     const_decl.name.lexeme, | ||||||
|                 }); |                 ); | ||||||
| 
 | 
 | ||||||
|                 printExpr(const_decl.expr); |                 printExpr(const_decl.expr); | ||||||
|                 std.debug.warn(")\n", .{}); |                 std.debug.warn(")\n"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             print(ident, "))\n", .{}); |             print(ident, "))\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Enum => |decl| { |         .Enum => |decl| { | ||||||
|             print(ident, "(enum {} (\n", .{decl.name.lexeme}); |             print(ident, "(enum {} (\n", decl.name.lexeme); | ||||||
| 
 | 
 | ||||||
|             for (decl.fields.items) |field| { |             for (decl.fields.toSlice()) |field| { | ||||||
|                 print(ident + 1, "{}\n", .{ |                 print( | ||||||
|  |                     ident + 1, | ||||||
|  |                     "{}\n", | ||||||
|                     field.lexeme, |                     field.lexeme, | ||||||
|                 }); |                 ); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             print(ident, "))\n", .{}); |             print(ident, "))\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Root => { |         .Root => { | ||||||
|             for (node.Root.items) |child| { |             for (node.Root.toSlice()) |child| { | ||||||
|                 printNode(child, ident + 1); |                 printNode(child, ident + 1); | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  | @ -100,129 +104,129 @@ pub fn printNode(node: *Node, ident: usize) void { | ||||||
|         .Stmt => |stmt| { |         .Stmt => |stmt| { | ||||||
|             printIdent(ident); |             printIdent(ident); | ||||||
|             printStmt(ident, stmt); |             printStmt(ident, stmt); | ||||||
|             std.debug.warn("\n", .{}); |             std.debug.warn("\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Struct => |struc| { |         .Struct => |struc| { | ||||||
|             print(ident, "(struct {} (\n", .{struc.name.lexeme}); |             print(ident, "(struct {} (\n", struc.name.lexeme); | ||||||
|             for (struc.fields.items) |field| { |             for (struc.fields.toSlice()) |field| { | ||||||
|                 printIdent(ident + 1); |                 printIdent(ident + 1); | ||||||
|                 if (field.mutable) { |                 if (field.mutable) { | ||||||
|                     std.debug.warn("(mut ", .{}); |                     std.debug.warn("(mut "); | ||||||
|                 } else { |                 } else { | ||||||
|                     std.debug.warn("(", .{}); |                     std.debug.warn("("); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (field.public) { |                 if (field.public) { | ||||||
|                     std.debug.warn("pub ", .{}); |                     std.debug.warn("pub "); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (field.mutable_outside) { |                 if (field.mutable_outside) { | ||||||
|                     std.debug.warn("MUT_OUT ", .{}); |                     std.debug.warn("MUT_OUT "); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 std.debug.warn("{} {})\n", .{ field.name.lexeme, field.typ.lexeme }); |                 std.debug.warn("{} {})\n", field.name.lexeme, field.typ.lexeme); | ||||||
|             } |             } | ||||||
|             print(ident, "))\n", .{}); |             print(ident, "))\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         else => { |         else => { | ||||||
|             print(ident, "unknown node: {}\n", .{node}); |             print(ident, "unknown node: {}\n", node); | ||||||
|         }, |         }, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn parenthetize(name: []const u8, exprs: []*const Expr) void { | fn parenthetize(name: []const u8, exprs: []*Expr) void { | ||||||
|     std.debug.warn("({}", .{name}); |     std.debug.warn("({}", name); | ||||||
| 
 | 
 | ||||||
|     for (exprs) |expr| { |     for (exprs) |expr| { | ||||||
|         std.debug.warn(" ", .{}); |         std.debug.warn(" "); | ||||||
|         printExpr(expr); |         printExpr(expr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std.debug.warn(")", .{}); |     std.debug.warn(")"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn printExpr(expr: *const Expr) void { | pub fn printExpr(expr: *Expr) void { | ||||||
|     switch (expr.*) { |     switch (expr.*) { | ||||||
|         .Binary => |binary| parenthetize(binary.op.lexeme, &[_]*const Expr{ binary.left, binary.right }), |         .Binary => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), | ||||||
|         .Logical => |binary| parenthetize(binary.op.lexeme, &[_]*const Expr{ binary.left, binary.right }), |         .Logical => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), | ||||||
|         .Unary => |unary| parenthetize(unary.op.lexeme, &[_]*const Expr{unary.right}), |         .Unary => |unary| parenthetize(unary.op.lexeme, &[_]*Expr{unary.right}), | ||||||
|         .Grouping => |expr_ptr| parenthetize("group", &[_]*const Expr{expr_ptr}), |         .Grouping => |expr_ptr| parenthetize("group", &[_]*Expr{expr_ptr}), | ||||||
| 
 | 
 | ||||||
|         .Literal => |literal| { |         .Literal => |literal| { | ||||||
|             switch (literal) { |             switch (literal) { | ||||||
|                 .Bool => |val| std.debug.warn("{}", .{val}), |                 .Bool => |val| std.debug.warn("{}", val), | ||||||
|                 .Integer => |val| std.debug.warn("{}", .{val}), |                 .Integer => |val| std.debug.warn("{}", val), | ||||||
|                 .Float => |val| std.debug.warn("{}", .{val}), |                 .Float => |val| std.debug.warn("{}", val), | ||||||
|                 .String => |val| std.debug.warn("'{}'", .{val}), |                 .String => |val| std.debug.warn("'{}'", val), | ||||||
|                 .Array => |exprs| { |                 .Array => |exprs| { | ||||||
|                     parenthetize("array", exprs.items); |                     parenthetize("array", exprs.toSlice()); | ||||||
|                 }, |                 }, | ||||||
|                 else => |typ| std.debug.warn("UnknownLiteral-{}", .{typ}), |                 else => |typ| std.debug.warn("UnknownLiteral-{}", typ), | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Variable => |token| std.debug.warn("{}", .{token.lexeme}), |         .Variable => |token| std.debug.warn("{}", token.lexeme), | ||||||
| 
 | 
 | ||||||
|         .VarDecl => |decl| { |         .VarDecl => |decl| { | ||||||
|             if (decl.mutable) { |             if (decl.mutable) { | ||||||
|                 std.debug.warn("(mut ", .{}); |                 std.debug.warn("(mut "); | ||||||
|             } else { |             } else { | ||||||
|                 std.debug.warn("(", .{}); |                 std.debug.warn("("); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std.debug.warn("let {} ", .{decl.assign.name.lexeme}); |             std.debug.warn("let {} ", decl.assign.name.lexeme); | ||||||
|             printExpr(decl.assign.value); |             printExpr(decl.assign.value); | ||||||
|             std.debug.warn(")", .{}); |             std.debug.warn(")"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Assign => |assign| { |         .Assign => |assign| { | ||||||
|             std.debug.warn("(set ", .{}); |             std.debug.warn("(set "); | ||||||
|             std.debug.warn("{} ", .{assign.name.lexeme}); |             std.debug.warn("{} ", assign.name.lexeme); | ||||||
|             printExpr(assign.value); |             printExpr(assign.value); | ||||||
|             std.debug.warn(")", .{}); |             std.debug.warn(")"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Call => |call| { |         .Call => |call| { | ||||||
|             std.debug.warn("(", .{}); |             std.debug.warn("("); | ||||||
|             printExpr(call.callee); |             printExpr(call.callee); | ||||||
| 
 | 
 | ||||||
|             for (call.arguments.items) |arg| { |             for (call.arguments.toSlice()) |arg| { | ||||||
|                 std.debug.warn(" ", .{}); |                 std.debug.warn(" "); | ||||||
|                 printExpr(arg); |                 printExpr(arg); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std.debug.warn(")", .{}); |             std.debug.warn(")"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Struct => |val| { |         .Struct => |val| { | ||||||
|             std.debug.warn("({} (", .{val.name.lexeme}); |             std.debug.warn("({} (", val.name.lexeme); | ||||||
| 
 | 
 | ||||||
|             for (val.inits.items) |init| { |             for (val.inits.toSlice()) |init| { | ||||||
|                 std.debug.warn(" ({} ", .{init.field.lexeme}); |                 std.debug.warn(" ({} ", init.field.lexeme); | ||||||
|                 printExpr(init.expr); |                 printExpr(init.expr); | ||||||
|                 std.debug.warn(")", .{}); |                 std.debug.warn(")"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std.debug.warn("))", .{}); |             std.debug.warn("))"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Get => |get| { |         .Get => |get| { | ||||||
|             warn("(", .{}); |             warn("("); | ||||||
|             printExpr(get.struc); |             printExpr(get.struc); | ||||||
|             warn("{}", .{get.name.lexeme}); |             warn(".{})", get.name.lexeme); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Set => |set| { |         .Set => |set| { | ||||||
|             warn("(set ", .{}); |             warn("(set "); | ||||||
|             printExpr(set.struc); |             printExpr(set.struc); | ||||||
|             warn(" {} ", .{set.field.lexeme}); |             warn(" {} ", set.field.lexeme); | ||||||
|             printExpr(set.value); |             printExpr(set.value); | ||||||
|             warn(")", .{}); |             warn(")"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         else => std.debug.warn("UnknownExpr-{}", .{@tagName(expr.*)}), |         else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -232,53 +236,38 @@ pub fn printStmt(ident: usize, stmt: *Stmt) void { | ||||||
|         .Expr => |expr| printExpr(expr), |         .Expr => |expr| printExpr(expr), | ||||||
| 
 | 
 | ||||||
|         .If => |ifstmt| { |         .If => |ifstmt| { | ||||||
|             std.debug.warn("(if ", .{}); |             std.debug.warn("(if "); | ||||||
|             printExpr(ifstmt.condition); |             printExpr(ifstmt.condition); | ||||||
|             std.debug.warn(" ", .{}); |             std.debug.warn(" "); | ||||||
| 
 | 
 | ||||||
|             printBlock(ident + 1, ifstmt.then_branch, false); |             printBlock(ident + 1, ifstmt.then_branch, false); | ||||||
|             if (ifstmt.else_branch) |else_branch| { |             if (ifstmt.else_branch) |else_branch| { | ||||||
|                 std.debug.warn(" else ", .{}); |                 std.debug.warn(" else "); | ||||||
|                 printBlock(ident + 1, else_branch, false); |                 printBlock(ident + 1, else_branch, false); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std.debug.warn(")\n", .{}); |             std.debug.warn(")\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Loop => |loop| { |         .Loop => |loop| { | ||||||
|             std.debug.warn("(loop ", .{}); |             std.debug.warn("(loop "); | ||||||
|             if (loop.condition) |cond| { |             if (loop.condition) |cond| { | ||||||
|                 printExpr(cond); |                 printExpr(cond); | ||||||
|             } else { |             } else { | ||||||
|                 std.debug.warn("true", .{}); |                 std.debug.warn("true"); | ||||||
|             } |             } | ||||||
|             std.debug.warn(" ", .{}); |             std.debug.warn(" "); | ||||||
| 
 | 
 | ||||||
|             printBlock(ident + 1, loop.then_branch, false); |             printBlock(ident + 1, loop.then_branch, false); | ||||||
|             std.debug.warn(")\n", .{}); |             std.debug.warn(")\n"); | ||||||
|         }, |  | ||||||
| 
 |  | ||||||
|         .For => |forstmt| { |  | ||||||
|             std.debug.warn("(for ", .{}); |  | ||||||
| 
 |  | ||||||
|             if (forstmt.index) |index| { |  | ||||||
|                 std.debug.warn("({} {}) ", .{ index.lexeme, forstmt.value.lexeme }); |  | ||||||
|             } else { |  | ||||||
|                 std.debug.warn("{} ", .{forstmt.value.lexeme}); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             std.debug.warn("{} ", .{forstmt.array.lexeme}); |  | ||||||
| 
 |  | ||||||
|             printBlock(ident + 1, forstmt.block, false); |  | ||||||
|             std.debug.warn(")\n", .{}); |  | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         .Return => |ret| { |         .Return => |ret| { | ||||||
|             std.debug.warn("(return ", .{}); |             std.debug.warn("(return "); | ||||||
|             printExpr(ret.value); |             printExpr(ret.value); | ||||||
|             std.debug.warn(")\n", .{}); |             std.debug.warn(")\n"); | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         else => std.debug.warn("UnknownStmt-{}", .{@tagName(stmt.*)}), |         else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| const std = @import("std"); | const std = @import("std"); | ||||||
| pub fn report(line: usize, where: []const u8, message: []const u8) void { | pub fn report(line: usize, where: []const u8, message: []const u8) void { | ||||||
|     std.debug.warn("[line {}] Error{}: {}", .{ line, where, message }); |     std.debug.warn("[line {}] Error{}: {}", line, where, message); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn reportN(line: usize, message: []const u8) void { | pub fn reportN(line: usize, message: []const u8) void { | ||||||
|     report(line, "", message); |     report(line, "", message); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn reportFmt(line: usize, comptime fmt: []const u8, args: anytype) void { | pub fn reportFmt(line: usize, comptime fmt: []const u8, args: ...) void { | ||||||
|     std.debug.warn("[line {}] Error", .{line}); |     std.debug.warn("[line {}] Error", line); | ||||||
|     std.debug.warn(fmt, args); |     std.debug.warn(fmt, args); | ||||||
|     std.debug.warn("\n", .{}); |     std.debug.warn("\n"); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								src/main.zig
									
										
									
									
									
								
							
							
						
						
									
										42
									
								
								src/main.zig
									
										
									
									
									
								
							|  | @ -10,16 +10,18 @@ pub const Result = error{ | ||||||
|     CompileError, |     CompileError, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| fn run(allocator: *Allocator, data: []const u8) !void { | pub const StdOut = *std.io.OutStream(std.fs.File.WriteError); | ||||||
|     var stdout_file = std.io.getStdOut(); | 
 | ||||||
|     const stdout = stdout_file.outStream(); | fn run(allocator: *Allocator, data: []u8) !void { | ||||||
|  |     var stdout_file = try std.io.getStdOut(); | ||||||
|  |     const stdout = &stdout_file.outStream().stream; | ||||||
| 
 | 
 | ||||||
|     var runner = runners.Runner.init(allocator, stdout); |     var runner = runners.Runner.init(allocator, stdout); | ||||||
|     return runner.execute(data); |     return runner.execute(data); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn runFile(allocator: *Allocator, path: []const u8) !void { | fn runFile(allocator: *Allocator, path: []const u8) !void { | ||||||
|     var file = try std.fs.cwd().openFile(path, .{}); |     var file = try std.fs.File.openRead(path); | ||||||
|     defer file.close(); |     defer file.close(); | ||||||
| 
 | 
 | ||||||
|     const total_bytes = try file.getEndPos(); |     const total_bytes = try file.getEndPos(); | ||||||
|  | @ -37,32 +39,26 @@ fn runFile(allocator: *Allocator, path: []const u8) !void { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn runPrompt(allocator: *Allocator) !void { | fn runPrompt(allocator: *Allocator) !void { | ||||||
|     var stdout_file = std.io.getStdOut(); |     var stdout_file = try std.io.getStdOut(); | ||||||
|     const stdout = stdout_file.outStream(); |     const stdout = &stdout_file.outStream().stream; | ||||||
| 
 |  | ||||||
|     var stdin_file = std.io.getStdIn(); |  | ||||||
|     const stdin = stdin_file.inStream(); |  | ||||||
| 
 |  | ||||||
|     var line_buf: [1024]u8 = undefined; |  | ||||||
| 
 | 
 | ||||||
|     while (true) { |     while (true) { | ||||||
|         try stdout.print("> ", .{}); |         try stdout.print("> "); | ||||||
|  |         var buffer = try std.Buffer.init(allocator, ""[0..]); | ||||||
| 
 | 
 | ||||||
|         const amt = try stdin.read(&line_buf); |         var line = std.io.readLine(&buffer) catch |err| { | ||||||
|         if (amt == line_buf.len) { |             if (err == error.EndOfStream) return; | ||||||
|             try stdout.print("Input too long.\n", .{}); |             return err; | ||||||
|             continue; |         }; | ||||||
|         } |  | ||||||
|         const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n"); |  | ||||||
| 
 | 
 | ||||||
|         run(allocator, line) catch |err| { |         run(allocator, line) catch |err| { | ||||||
|             switch (err) { |             switch (err) { | ||||||
|                 Result.Ok => {}, |                 Result.Ok => {}, | ||||||
|                 Result.ScannerError => blk: { |                 Result.ScannerError => blk: { | ||||||
|                     try stdout.print("scanner error.\n", .{}); |                     try stdout.print("scanner error.\n"); | ||||||
|                 }, |                 }, | ||||||
|                 Result.CompileError => blk: { |                 Result.CompileError => blk: { | ||||||
|                     try stdout.print("compile error.\n", .{}); |                     try stdout.print("compile error.\n"); | ||||||
|                 }, |                 }, | ||||||
|                 else => return err, |                 else => return err, | ||||||
|             } |             } | ||||||
|  | @ -71,12 +67,12 @@ fn runPrompt(allocator: *Allocator) !void { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn main() anyerror!void { | pub fn main() anyerror!void { | ||||||
|     var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); |     var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator); | ||||||
|     defer arena.deinit(); |     defer arena.deinit(); | ||||||
|     var allocator = &arena.allocator; |     var allocator = &arena.allocator; | ||||||
| 
 | 
 | ||||||
|     var stdout_file = std.io.getStdOut(); |     var stdout_file = try std.io.getStdOut(); | ||||||
|     var stdout = stdout_file.outStream(); |     var stdout = &stdout_file.outStream().stream; | ||||||
| 
 | 
 | ||||||
|     var args_it = std.process.args(); |     var args_it = std.process.args(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,27 +43,27 @@ pub const Parser = struct { | ||||||
|         self.tokens.deinit(); |         self.tokens.deinit(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn doError(self: *Parser, comptime fmt: []const u8, args: anytype) void { |     fn doError(self: *Parser, comptime fmt: []const u8, args: ...) void { | ||||||
|         self.hadError = true; |         self.hadError = true; | ||||||
| 
 | 
 | ||||||
|         std.debug.warn("parser error at line {}\n\t", .{self.scanner.line}); |         std.debug.warn("parser error at line {}\n\t", self.scanner.line); | ||||||
|         std.debug.warn(fmt, args); |         std.debug.warn(fmt, args); | ||||||
|         std.debug.warn("\n", .{}); |         std.debug.warn("\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn peek(self: *Parser) Token { |     fn peek(self: *Parser) Token { | ||||||
|         return self.tokens.items[self.tokens.items.len - 1]; |         return self.tokens.at(self.tokens.len - 1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn previous(self: *Parser) Token { |     fn previous(self: *Parser) Token { | ||||||
|         return self.tokens.items[self.tokens.items.len - 2]; |         return self.tokens.at(self.tokens.len - 2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn tokenError(self: *Parser, token: Token, msg: []const u8) Result!void { |     fn tokenError(self: *Parser, token: Token, msg: []const u8) Result!void { | ||||||
|         if (token.ttype == .EOF) { |         if (token.ttype == .EOF) { | ||||||
|             err.report(token.line, " at end", msg); |             err.report(token.line, " at end", msg); | ||||||
|         } else { |         } else { | ||||||
|             err.reportFmt(token.line, " at '{}': {}", .{ token.lexeme, msg }); |             err.reportFmt(token.line, " at '{}': {}", token.lexeme, msg); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return Result.CompileError; |         return Result.CompileError; | ||||||
|  | @ -90,7 +90,7 @@ pub const Parser = struct { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try self.tokens.append(token); |         try self.tokens.append(token); | ||||||
|         std.debug.warn("skip to {}\n", .{token}); |         std.debug.warn("skip to {}\n", token); | ||||||
|         return token; |         return token; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -117,17 +117,19 @@ pub const Parser = struct { | ||||||
| 
 | 
 | ||||||
|         // TODO maybe this could be entirely comptime? |         // TODO maybe this could be entirely comptime? | ||||||
|         var buf_main: [1000]u8 = undefined; |         var buf_main: [1000]u8 = undefined; | ||||||
|         var buf = try std.fmt.bufPrint(buf_main[0..], "expected {}, got {}", .{ |         var buf = try std.fmt.bufPrint( | ||||||
|  |             buf_main[0..], | ||||||
|  |             "expected {}, got {}", | ||||||
|             ttype, |             ttype, | ||||||
|             self.peek().ttype, |             self.peek().ttype, | ||||||
|         }); |         ); | ||||||
| 
 | 
 | ||||||
|         try self.tokenError(self.peek(), buf); |         try self.tokenError(self.peek(), buf); | ||||||
|         return Result.CompileError; |         return Result.CompileError; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// check() against multiple tokens |     /// check() against multiple tokens | ||||||
|     fn compareAnyOf(self: *@This(), ttypes: []const TokenType) bool { |     fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool { | ||||||
|         for (ttypes) |ttype| { |         for (ttypes) |ttype| { | ||||||
|             if (self.check(ttype)) return true; |             if (self.check(ttype)) return true; | ||||||
|         } |         } | ||||||
|  | @ -189,7 +191,7 @@ pub const Parser = struct { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr { |     fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr { | ||||||
|         std.debug.warn("Unary\n", .{}); |         std.debug.warn("Unary\n"); | ||||||
| 
 | 
 | ||||||
|         var expr = try self.allocator.create(Expr); |         var expr = try self.allocator.create(Expr); | ||||||
|         expr.* = Expr{ |         expr.* = Expr{ | ||||||
|  | @ -607,7 +609,7 @@ pub const Parser = struct { | ||||||
|             .Enum => try self.parseEnumDecl(), |             .Enum => try self.parseEnumDecl(), | ||||||
| 
 | 
 | ||||||
|             else => |ttype| blk: { |             else => |ttype| blk: { | ||||||
|                 self.doError("expected Fn, Const, Struct, got {}\n", .{ttype}); |                 self.doError("expected Fn, Const, Struct, got {}\n", ttype); | ||||||
|                 return Result.CompileError; |                 return Result.CompileError; | ||||||
|             }, |             }, | ||||||
|         }; |         }; | ||||||
|  | @ -634,7 +636,6 @@ pub const Parser = struct { | ||||||
|         return switch (self.peek().ttype) { |         return switch (self.peek().ttype) { | ||||||
|             .If => try self.parseIfStmt(), |             .If => try self.parseIfStmt(), | ||||||
|             .Loop => try self.parseLoop(), |             .Loop => try self.parseLoop(), | ||||||
|             .For => try self.parseForStmt(), |  | ||||||
|             .Println => try self.parsePrintln(), |             .Println => try self.parsePrintln(), | ||||||
|             .Return => try self.parseReturn(), |             .Return => try self.parseReturn(), | ||||||
|             else => try self.parseStmtExpr(), |             else => try self.parseStmtExpr(), | ||||||
|  | @ -674,42 +675,6 @@ pub const Parser = struct { | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn parseForStmt(self: *@This()) !*Stmt { |  | ||||||
|         // There are two types of for in vig's V subset: |  | ||||||
|         //  - for x in y |  | ||||||
|         //  - for idx, x in y |  | ||||||
|         _ = try self.consumeSingle(.For); |  | ||||||
| 
 |  | ||||||
|         var index_var: ?Token = null; |  | ||||||
|         var value_var: Token = undefined; |  | ||||||
| 
 |  | ||||||
|         const subject_1 = try self.consumeSingle(.Identifier); |  | ||||||
| 
 |  | ||||||
|         if (self.check(.Comma)) { |  | ||||||
|             _ = try self.consumeSingle(.Comma); |  | ||||||
| 
 |  | ||||||
|             const subject_2 = try self.consumeSingle(.Identifier); |  | ||||||
|             index_var = subject_1; |  | ||||||
|             value_var = subject_2; |  | ||||||
|         } else { |  | ||||||
|             value_var = subject_1; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         _ = try self.consumeSingle(.In); |  | ||||||
| 
 |  | ||||||
|         // MUST be identifier |  | ||||||
|         var array = try self.consumeSingle(.Identifier); |  | ||||||
|         var block = try self.parseStmtBlock(); |  | ||||||
| 
 |  | ||||||
|         return try Stmt.mkFor( |  | ||||||
|             self.allocator, |  | ||||||
|             index_var, |  | ||||||
|             value_var, |  | ||||||
|             array, |  | ||||||
|             block, |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn parseLoop(self: *@This()) !*Stmt { |     fn parseLoop(self: *@This()) !*Stmt { | ||||||
|         _ = try self.consumeSingle(.Loop); |         _ = try self.consumeSingle(.Loop); | ||||||
|         var expr: ?*Expr = null; |         var expr: ?*Expr = null; | ||||||
|  | @ -837,7 +802,7 @@ pub const Parser = struct { | ||||||
|             .Get => |get| { |             .Get => |get| { | ||||||
|                 switch (op.ttype) { |                 switch (op.ttype) { | ||||||
|                     .ColonEqual => { |                     .ColonEqual => { | ||||||
|                         self.doError("can not initialize struct field", .{}); |                         self.doError("can not initialize struct field"); | ||||||
|                         return Result.CompileError; |                         return Result.CompileError; | ||||||
|                     }, |                     }, | ||||||
| 
 | 
 | ||||||
|  | @ -857,7 +822,7 @@ pub const Parser = struct { | ||||||
|             }, |             }, | ||||||
| 
 | 
 | ||||||
|             else => |expr_typ| { |             else => |expr_typ| { | ||||||
|                 self.doError("Invalid assignment target {}", .{expr_typ}); |                 self.doError("Invalid assignment target {}", expr_typ); | ||||||
|                 return Result.CompileError; |                 return Result.CompileError; | ||||||
|             }, |             }, | ||||||
|         } |         } | ||||||
|  | @ -1027,8 +992,8 @@ pub const Parser = struct { | ||||||
|     fn finishStructVal(self: *@This(), expr: *Expr) !*Expr { |     fn finishStructVal(self: *@This(), expr: *Expr) !*Expr { | ||||||
|         // <expr>{a: 10 b: 10} |         // <expr>{a: 10 b: 10} | ||||||
|         // for this to work properly, <expr> must be Variable, since its a type. |         // for this to work properly, <expr> must be Variable, since its a type. | ||||||
|         if (@as(ast.ExprType, expr.*) != .Variable) { |         if (ast.ExprType(expr.*) != .Variable) { | ||||||
|             self.doError("Expected variable for struct type, got {}", .{@as(ast.ExprType, expr.*)}); |             self.doError("Expected variable for struct type, got {}", ast.ExprType(expr.*)); | ||||||
|             return Result.CompileError; |             return Result.CompileError; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -1093,7 +1058,7 @@ pub const Parser = struct { | ||||||
|             }, |             }, | ||||||
| 
 | 
 | ||||||
|             else => blk: { |             else => blk: { | ||||||
|                 self.doError("expected literal, got {}", .{curtype}); |                 self.doError("expected literal, got {}", curtype); | ||||||
|                 return Result.CompileError; |                 return Result.CompileError; | ||||||
|             }, |             }, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|  | @ -13,31 +13,32 @@ const Parser = parsers.Parser; | ||||||
| 
 | 
 | ||||||
| pub const Runner = struct { | pub const Runner = struct { | ||||||
|     allocator: *Allocator, |     allocator: *Allocator, | ||||||
|     stdout: std.fs.File.OutStream, |     stdout: main.StdOut, | ||||||
| 
 | 
 | ||||||
|     pub fn init(allocator: *Allocator, stdout: anytype) Runner { |     pub fn init(allocator: *Allocator, stdout: main.StdOut) Runner { | ||||||
|         return .{ .allocator = allocator, .stdout = stdout }; |         return Runner{ .allocator = allocator, .stdout = stdout }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn testScanner(self: *Runner, scanner: *scanners.Scanner) !void { |     fn testScanner(self: *Runner, scanner: *scanners.Scanner) !void { | ||||||
|         while (true) { |         while (true) { | ||||||
|             var tok_opt = scanner.nextToken() catch |err| { |             var tok_opt = scanner.nextToken() catch |err| { | ||||||
|                 try self.stdout.print("error at '{}': {}\n", .{ |                 try self.stdout.print( | ||||||
|  |                     "error at '{}': {}\n", | ||||||
|                     scanner.currentLexeme(), |                     scanner.currentLexeme(), | ||||||
|                     err, |                     err, | ||||||
|                 }); |                 ); | ||||||
| 
 | 
 | ||||||
|                 return Result.ScannerError; |                 return Result.ScannerError; | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             if (tok_opt) |tok| { |             if (tok_opt) |tok| { | ||||||
|                 if (tok.ttype == .EOF) break; |                 if (tok.ttype == .EOF) break; | ||||||
|                 try self.stdout.print("{x}\n", .{tok}); |                 try self.stdout.print("{x}\n", tok); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn execute(self: *Runner, code: []const u8) !void { |     pub fn execute(self: *Runner, code: []u8) !void { | ||||||
|         var scanner = scanners.Scanner.init(self.allocator, code); |         var scanner = scanners.Scanner.init(self.allocator, code); | ||||||
|         try self.testScanner(&scanner); |         try self.testScanner(&scanner); | ||||||
| 
 | 
 | ||||||
|  | @ -45,9 +46,9 @@ pub const Runner = struct { | ||||||
|         var parser = Parser.init(self.allocator, &scanner); |         var parser = Parser.init(self.allocator, &scanner); | ||||||
|         var root = try parser.parse(); |         var root = try parser.parse(); | ||||||
| 
 | 
 | ||||||
|         // var it = root.Root.iterator(); |         var it = root.Root.iterator(); | ||||||
| 
 | 
 | ||||||
|         std.debug.warn("parse tree\n", .{}); |         std.debug.warn("parse tree\n"); | ||||||
|         printer.printNode(root, 0); |         printer.printNode(root, 0); | ||||||
| 
 | 
 | ||||||
|         return Result.Ok; |         return Result.Ok; | ||||||
|  |  | ||||||
|  | @ -97,13 +97,13 @@ fn getKeyword(keyword: []const u8) ?TokenType { | ||||||
| /// Scanner for vlang tokens. | /// Scanner for vlang tokens. | ||||||
| pub const Scanner = struct { | pub const Scanner = struct { | ||||||
|     allocator: *Allocator, |     allocator: *Allocator, | ||||||
|     source: []const u8, |     source: []u8, | ||||||
| 
 | 
 | ||||||
|     start: usize = 0, |     start: usize = 0, | ||||||
|     current: usize = 0, |     current: usize = 0, | ||||||
|     line: usize = 1, |     line: usize = 1, | ||||||
| 
 | 
 | ||||||
|     pub fn init(allocator: *Allocator, source: []const u8) Scanner { |     pub fn init(allocator: *Allocator, source: []u8) Scanner { | ||||||
|         return Scanner{ .allocator = allocator, .source = source }; |         return Scanner{ .allocator = allocator, .source = source }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue