Compare commits

..

No commits in common. "ec652b29d91ec247a68ea6724bc1b92bac8c4557" and "0f8e19adf18c663b1b0fdc2f1d76c7b9e752cd0f" have entirely different histories.

5 changed files with 31 additions and 111 deletions

View file

@ -167,6 +167,8 @@ pub const Compiler = struct {
if (token_opt) |token| { if (token_opt) |token| {
self.parser.current = token; self.parser.current = token;
break; break;
} else {
self.errorCurrent(self.parser.current.lexeme);
} }
} }
} }
@ -219,12 +221,11 @@ pub const Compiler = struct {
/// Emits bytecode for a number being loaded into the code. /// Emits bytecode for a number being loaded into the code.
fn number(self: *Compiler) !void { fn number(self: *Compiler) !void {
std.debug.warn("parsing number: '{}'\n", self.parser.previous.lexeme);
var value: f64 = try std.fmt.parseFloat( var value: f64 = try std.fmt.parseFloat(
f64, f64,
self.parser.previous.lexeme, self.parser.previous.lexeme,
); );
try self.emitConstant(values.NumberVal(value)); try self.emitConstant(value);
} }
/// Emits bytecode for a given unary. /// Emits bytecode for a given unary.

View file

@ -12,12 +12,12 @@ const InterpretResult = vm.InterpretResult;
pub var hadError = false; pub var hadError = false;
fn run(allocator: *Allocator, data: []u8) !void { fn run(allocator: *Allocator, data: []u8) !InterpretResult {
var stdout_file = try std.io.getStdOut(); var stdout_file = try std.io.getStdOut();
const stdout = &stdout_file.outStream().stream; const stdout = &stdout_file.outStream().stream;
var vmach = try vm.VM.init(allocator, stdout, data, true); var vmach = try vm.VM.init(allocator, stdout, data, true);
try vmach.interpret(); return try vmach.interpret();
} }
pub fn doError(line: usize, message: []const u8) !void { pub fn doError(line: usize, message: []const u8) !void {
@ -40,14 +40,9 @@ fn runFile(allocator: *Allocator, path: []const u8) !void {
var slice = try allocator.alloc(u8, total_bytes); var slice = try allocator.alloc(u8, total_bytes);
_ = try lox_file.read(slice); _ = try lox_file.read(slice);
run(allocator, slice) catch |err| { var res = try run(allocator, slice);
switch (err) { if (res == vm.InterpretResult.CompileError) std.os.exit(65);
InterpretResult.Ok => {}, if (res == vm.InterpretResult.RuntimeError) std.os.exit(70);
InterpretResult.CompileError => std.os.exit(65),
InterpretResult.RuntimeError => std.os.exit(70),
else => return err,
}
};
} }
fn runPrompt(allocator: *Allocator) !void { fn runPrompt(allocator: *Allocator) !void {
@ -64,15 +59,7 @@ fn runPrompt(allocator: *Allocator) !void {
return err; return err;
}; };
run(allocator, line) catch |err| { _ = try run(allocator, line);
switch (err) {
InterpretResult.Ok => {},
InterpretResult.CompileError, InterpretResult.RuntimeError => blk: {
try stdout.print("compile/runtime error.\n");
},
else => return err,
}
};
} }
} }

View file

@ -147,8 +147,8 @@ pub const Scanner = struct {
} }
fn peekNext(self: *Scanner) u8 { fn peekNext(self: *Scanner) u8 {
if (self.current + 1 >= self.source.len) return 0; if (self.isAtEnd()) return 0;
return self.source[self.current + 1]; return self.source[self.current - 1];
} }
fn skipWhitespace(self: *Scanner) void { fn skipWhitespace(self: *Scanner) void {
@ -259,7 +259,6 @@ pub const Scanner = struct {
while (self.peek() != '\n' and !self.isAtEnd()) { while (self.peek() != '\n' and !self.isAtEnd()) {
_ = self.advance(); _ = self.advance();
} }
break :blk null; break :blk null;
} else { } else {
break :blk self.makeToken(.SLASH); break :blk self.makeToken(.SLASH);

View file

@ -3,42 +3,10 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
// NOTE: right now, only numbers. // NOTE: right now, only numbers.
pub const Value = f64;
pub const ValueType = enum(u8) {
Bool,
Nil,
Number,
};
pub const ValueValue = union(ValueType) {
Bool: bool,
Nil: void,
Number: f64,
};
pub const Value = struct {
vtype: ValueType,
as: ValueValue,
};
// helper functions
pub fn BoolVal(val: bool) Value {
return Value{ .vtype = .Bool, .as = ValueValue{ .Bool = val } };
}
pub fn NilVal() Value {
return Value{ .vtype = .Nil, .as = ValueValue{ .Nil = {} } };
}
pub fn NumberVal(val: f64) Value {
return Value{ .vtype = .Number, .as = ValueValue{ .Number = val } };
}
pub fn printValue(stdout: var, value: Value) !void { pub fn printValue(stdout: var, value: Value) !void {
switch (value.as) { try stdout.print("{}", value);
.Number => try stdout.print("{}", value.as.Number),
else => unreachable,
}
} }
pub const ValueList = struct { pub const ValueList = struct {

View file

@ -1,7 +1,6 @@
const std = @import("std"); const std = @import("std");
const chunk = @import("chunk.zig"); const chunk = @import("chunk.zig");
const value = @import("value.zig"); const value = @import("value.zig");
const values = value;
const compiler = @import("compiler.zig"); const compiler = @import("compiler.zig");
const Chunk = chunk.Chunk; const Chunk = chunk.Chunk;
@ -10,7 +9,7 @@ const Compiler = compiler.Compiler;
pub const StdOut = *std.io.OutStream(std.fs.File.WriteError); pub const StdOut = *std.io.OutStream(std.fs.File.WriteError);
pub const InterpretResult = error{ pub const InterpretResult = enum {
Ok, Ok,
CompileError, CompileError,
RuntimeError, RuntimeError,
@ -92,50 +91,35 @@ pub const VM = struct {
} }
/// gets a f64 out of a value on the top of the stack. /// gets a f64 out of a value on the top of the stack.
fn popNum(self: *VM) !f64 { fn popNum(self: *VM) f64 {
var val: Value = self.pop(); return self.pop();
switch (val.vtype) {
.Number => return val.as.Number,
else => |vtype| blk: {
self.runtimeError("Expected number, got {x}", vtype);
return InterpretResult.RuntimeError;
},
}
} }
fn doAdd(self: *VM) !void { fn doAdd(self: *VM) !void {
var b = try self.popNum(); var b = self.popNum();
var a = try self.popNum(); var a = self.popNum();
try self.push(values.NumberVal(a + b)); try self.push(a + b);
} }
fn doSub(self: *VM) !void { fn doSub(self: *VM) !void {
var b = try self.popNum(); var b = self.popNum();
var a = try self.popNum(); var a = self.popNum();
try self.push(values.NumberVal(a - b)); try self.push(a * b);
} }
fn doMul(self: *VM) !void { fn doMul(self: *VM) !void {
var b = try self.popNum(); var b = self.popNum();
var a = try self.popNum(); var a = self.popNum();
try self.push(values.NumberVal(a * b)); try self.push(a * b);
} }
fn doDiv(self: *VM) !void { fn doDiv(self: *VM) !void {
var b = try self.popNum(); var b = self.popNum();
var a = try self.popNum(); var a = self.popNum();
try self.push(values.NumberVal(a / b)); try self.push(a / b);
} }
fn runtimeError(self: *VM, comptime fmt: []const u8, args: ...) void { fn run(self: *VM) !InterpretResult {
std.debug.warn(fmt, args);
std.debug.warn("\n[line {}] in script\n", self.chk.lines[self.ip]);
self.resetStack();
}
fn run(self: *VM) !void {
while (true) { while (true) {
if (self.debug_flag) { if (self.debug_flag) {
try self.debugStack(); try self.debugStack();
@ -166,22 +150,7 @@ pub const VM = struct {
chunk.OpCode.Subtract => try self.doSub(), chunk.OpCode.Subtract => try self.doSub(),
chunk.OpCode.Multiply => try self.doMul(), chunk.OpCode.Multiply => try self.doMul(),
chunk.OpCode.Divide => try self.doDiv(), chunk.OpCode.Divide => try self.doDiv(),
chunk.OpCode.Negate => blk: { chunk.OpCode.Negate => try self.push(-self.pop()),
var val = self.peek(0);
if (val.vtype != .Bool) {
self.runtimeError("Operand must be a number.");
return InterpretResult.RuntimeError;
}
val = self.pop();
switch (val.as) {
.Number => |num| {
try self.push(values.NumberVal(-num));
},
else => unreachable,
}
},
else => blk: { else => blk: {
std.debug.warn("Unknown instruction: {x}\n", instruction); std.debug.warn("Unknown instruction: {x}\n", instruction);
return InterpretResult.RuntimeError; return InterpretResult.RuntimeError;
@ -190,7 +159,7 @@ pub const VM = struct {
} }
} }
pub fn interpret(self: *VM) !void { pub fn interpret(self: *VM) !InterpretResult {
//self.ip = 0; //self.ip = 0;
//self.debug("VM start\n"); //self.debug("VM start\n");
//var res = try self.run(); //var res = try self.run();
@ -227,8 +196,4 @@ pub const VM = struct {
self.stackTop -= 1; self.stackTop -= 1;
return self.stack[self.stackTop]; return self.stack[self.stackTop];
} }
pub fn peek(self: *VM, distance: usize) Value {
return self.stack[self.stackTop - 1 - distance];
}
}; };