aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjjanzen <jjanzen@jjanzen.ca>2025-02-27 17:40:58 -0600
committerjjanzen <jjanzen@jjanzen.ca>2025-02-27 17:40:58 -0600
commit4af81abcc1c9555011677da25b89061ce6bc605e (patch)
treeab4a5bdc6d0b0f831bbece809ea809f929579073
parenta316be56e292baa2599cc6f08f616196d44c08a6 (diff)
handle more edge cases
-rw-r--r--src/parser.zig159
-rw-r--r--src/temp.py153
2 files changed, 124 insertions, 188 deletions
diff --git a/src/parser.zig b/src/parser.zig
index 9445fee..51ea0ac 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -240,6 +240,16 @@ pub const Parser = struct {
const SymbolError = error{
UnexpectedSymbol,
+ ForwardReference0,
+ ForwardReference1,
+ ForwardReference2,
+ ForwardReference3,
+ ForwardReference4,
+ ForwardReference5,
+ ForwardReference6,
+ ForwardReference7,
+ ForwardReference8,
+ ForwardReference9,
};
/// Determine whether the cursor points at a symbol
@@ -270,8 +280,25 @@ pub const Parser = struct {
}
/// Get the number associated with a given symbol
- fn handleSymbol(self: *Parser, symbol: []const u8) SymbolError!NumberValue {
- // TODO: handle xH, XF, xB
+ fn readSymbol(self: *Parser, symbol: []const u8) SymbolError!NumberValue {
+ if (symbol.len == 2 and symbol[0] >= '0' and symbol[0] <= '9' and symbol[1] != 'B') {
+ if (symbol[1] != 'F') return SymbolError.UnexpectedSymbol;
+
+ return switch (symbol[0]) {
+ '0' => SymbolError.ForwardReference0,
+ '1' => SymbolError.ForwardReference1,
+ '2' => SymbolError.ForwardReference2,
+ '3' => SymbolError.ForwardReference3,
+ '4' => SymbolError.ForwardReference4,
+ '5' => SymbolError.ForwardReference5,
+ '6' => SymbolError.ForwardReference6,
+ '7' => SymbolError.ForwardReference7,
+ '8' => SymbolError.ForwardReference8,
+ '9' => SymbolError.ForwardReference9,
+ else => unreachable,
+ };
+ }
+
const n = self.symbols.get(symbol);
if (n == null) return SymbolError.UnexpectedSymbol;
return n.?;
@@ -289,7 +316,7 @@ pub const Parser = struct {
NoEndingDelimiter,
UnaryOperationOnString,
BinaryOperationOnString,
- InvalidOperationOnRegister,
+ IllegalOperationOnRegister,
DivisionByZero,
FractionalDivisionOversizedNumerator,
};
@@ -300,16 +327,23 @@ pub const Parser = struct {
var result: u64 = 0;
var last_op = WeakOp.none;
var done = false;
+ var started = false;
var register_result: ?u8 = null;
var string_result: ?[]const u8 = null;
while (!done) {
if (string_result != null) return ExpressionError.BinaryOperationOnString;
- if (register_result != null) return ExpressionError.InvalidOperationOnRegister;
+ if (register_result != null) return ExpressionError.IllegalOperationOnRegister;
const term = try self.identifyTerm();
switch (term) {
- .string => string_result = term.string,
+ .string => {
+ if (!started) {
+ string_result = term.string;
+ } else {
+ return ExpressionError.BinaryOperationOnString;
+ }
+ },
.number => |nv| {
switch (nv) {
.pure => |n| {
@@ -321,7 +355,13 @@ pub const Parser = struct {
WeakOp.none => n,
};
},
- .register => register_result = nv.register,
+ .register => {
+ if (!started) {
+ register_result = nv.register;
+ } else {
+ return ExpressionError.IllegalOperationOnRegister;
+ }
+ },
}
},
}
@@ -339,6 +379,8 @@ pub const Parser = struct {
} else {
self.ch_pos += 1;
}
+
+ started = true;
}
if (string_result != null) {
@@ -373,7 +415,7 @@ pub const Parser = struct {
var done = false;
while (!done) {
if (string_result != null) return ExpressionError.BinaryOperationOnString;
- if (register_result != null) return ExpressionError.InvalidOperationOnRegister;
+ if (register_result != null) return ExpressionError.IllegalOperationOnRegister;
const primary = try self.identifyPrimary();
@@ -415,7 +457,7 @@ pub const Parser = struct {
if (!started) {
register_result = nv.register;
} else {
- return ExpressionError.InvalidOperationOnRegister;
+ return ExpressionError.IllegalOperationOnRegister;
}
},
}
@@ -485,7 +527,7 @@ pub const Parser = struct {
const symbol = try self.identifySymbol();
if (symbol.len != 2) return SymbolError.UnexpectedSymbol;
if (symbol[1] == 'H') return SymbolError.UnexpectedSymbol;
- const symbol_val = try self.handleSymbol(symbol);
+ const symbol_val = try self.readSymbol(symbol);
return ExpressionResult{ .number = symbol_val };
}
@@ -555,7 +597,7 @@ pub const Parser = struct {
},
else => {
const symbol = try self.identifySymbol();
- const symbol_value = try self.handleSymbol(symbol);
+ const symbol_value = try self.readSymbol(symbol);
return ExpressionResult{ .number = symbol_value };
},
}
@@ -574,8 +616,8 @@ pub const Parser = struct {
return opcodes.parseOp(self.allocator, self.input[start..end]);
}
- pub fn init(allocator: std.mem.Allocator, input: []const u8) Parser {
- return Parser{
+ pub fn init(allocator: std.mem.Allocator, input: []const u8) !Parser {
+ var p = Parser{
.allocator = allocator,
.input = input,
.location = 0,
@@ -583,6 +625,19 @@ pub const Parser = struct {
.symbols = std.StringHashMap(NumberValue).init(allocator),
.object = std.ArrayList(u8).init(allocator),
};
+
+ try p.symbols.put("0B", NumberValue{ .pure = 0 });
+ try p.symbols.put("1B", NumberValue{ .pure = 0 });
+ try p.symbols.put("2B", NumberValue{ .pure = 0 });
+ try p.symbols.put("3B", NumberValue{ .pure = 0 });
+ try p.symbols.put("4B", NumberValue{ .pure = 0 });
+ try p.symbols.put("5B", NumberValue{ .pure = 0 });
+ try p.symbols.put("6B", NumberValue{ .pure = 0 });
+ try p.symbols.put("7B", NumberValue{ .pure = 0 });
+ try p.symbols.put("8B", NumberValue{ .pure = 0 });
+ try p.symbols.put("9B", NumberValue{ .pure = 0 });
+
+ return p;
}
pub fn deinit(self: *Parser) void {
@@ -635,7 +690,7 @@ test "symbols are identified" {
};
for (0..6) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = try parser.identifySymbol();
try std.testing.expect(std.mem.eql(u8, expected[i], symbol));
parser.deinit();
@@ -650,7 +705,7 @@ test "no symbols are found successfully" {
};
for (test_cases) |case| {
- var parser = Parser.init(std.testing.allocator, case);
+ var parser = try Parser.init(std.testing.allocator, case);
const symbol = parser.identifySymbol();
try std.testing.expectEqual(error.UnexpectedSymbol, symbol);
parser.deinit();
@@ -675,7 +730,7 @@ test "opcodes are identified" {
};
for (0..5) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const op = try parser.identifyOperation();
try std.testing.expectEqual(expected[i], op);
parser.deinit();
@@ -691,7 +746,7 @@ test "no opcodes are found successfully" {
};
for (test_cases) |case| {
- var parser = Parser.init(std.testing.allocator, case);
+ var parser = try Parser.init(std.testing.allocator, case);
const symbol = parser.identifyOperation();
try std.testing.expectEqual(error.NoOpcode, symbol);
parser.deinit();
@@ -712,7 +767,7 @@ test "decimals are recognized" {
};
for (0..3) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = try parser.identifyDecimal();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -735,7 +790,7 @@ test "malformed decimals are not recognized" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = parser.identifyDecimal();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -756,7 +811,7 @@ test "hexadecimals are recognized" {
};
for (0..3) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = try parser.identifyHexadecimal();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -781,7 +836,7 @@ test "malformed hexadecimals are not recognized" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = parser.identifyHexadecimal();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -802,7 +857,7 @@ test "characters are recognized" {
};
for (0..3) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = try parser.identifyChar();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -829,7 +884,7 @@ test "invalid unicode sequences are not characters" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = parser.identifyChar();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -848,7 +903,7 @@ test "strings are recognized" {
};
for (0..2) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = try parser.identifyString();
try std.testing.expect(std.mem.eql(u8, expected[i], symbol));
parser.deinit();
@@ -871,7 +926,7 @@ test "invalid strings are not recognized" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
const symbol = parser.identifyString();
try std.testing.expectEqual(expected[i], symbol);
parser.deinit();
@@ -894,7 +949,7 @@ test "constants are recognized" {
};
for (0..4) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
const symbol = try parser.identifyConstant();
switch (symbol) {
@@ -918,7 +973,7 @@ test "invalid constants are recognized" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
const symbol = parser.identifyConstant();
try std.testing.expectEqual(expected[i], symbol);
@@ -949,7 +1004,7 @@ test "basic primaries are identified" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
const symbol = try parser.identifyPrimary();
switch (symbol) {
@@ -973,7 +1028,7 @@ test "invalid primaries are detected" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
const symbol = parser.identifyPrimary();
try std.testing.expectEqual(expected[i], symbol);
@@ -1006,7 +1061,7 @@ test "valid terms are recognized" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
const symbol = try parser.identifyTerm();
@@ -1031,7 +1086,7 @@ test "terms compute the entire chain" {
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
const symbol = try parser.identifyTerm();
try std.testing.expectEqual(expected[i], symbol);
@@ -1049,10 +1104,10 @@ test "strong operations do not work on registers" {
};
for (test_cases) |case| {
- var parser = Parser.init(std.testing.allocator, case);
+ var parser = try Parser.init(std.testing.allocator, case);
defer parser.deinit();
const symbol = parser.identifyTerm();
- try std.testing.expectEqual(Parser.ExpressionError.InvalidOperationOnRegister, symbol);
+ try std.testing.expectEqual(Parser.ExpressionError.IllegalOperationOnRegister, symbol);
}
}
@@ -1063,7 +1118,7 @@ test "strong operations do not work on strings" {
};
for (test_cases) |case| {
- var parser = Parser.init(std.testing.allocator, case);
+ var parser = try Parser.init(std.testing.allocator, case);
defer parser.deinit();
const symbol = parser.identifyTerm();
try std.testing.expectEqual(Parser.ExpressionError.BinaryOperationOnString, symbol);
@@ -1079,9 +1134,10 @@ test "expressions are recognized" {
"#AA^#FF",
"5*5+5",
"5*5+5*5",
- "#ab<<32+#cdef00&~(#cdef00-1)",
+ "#ab<<32+k&~(k-1)",
"\"hello\"",
"$12",
+ "$$12",
};
const expected = [_]ExpressionResult{
@@ -1095,11 +1151,15 @@ test "expressions are recognized" {
ExpressionResult{ .number = NumberValue{ .pure = 0xab00000100 } },
ExpressionResult{ .string = "hello" },
ExpressionResult{ .number = NumberValue{ .register = 12 } },
+ ExpressionResult{ .number = NumberValue{ .register = 12 } },
};
for (0..test_cases.len) |i| {
- var parser = Parser.init(std.testing.allocator, test_cases[i]);
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
defer parser.deinit();
+
+ try parser.symbols.put("k", NumberValue{ .pure = 0xcdef00 });
+
const symbol = try parser.identifyExpression();
switch (symbol) {
@@ -1108,3 +1168,32 @@ test "expressions are recognized" {
}
}
}
+
+test "weak operations cannot be applied to strings and registers" {
+ const test_cases = [_][]const u8{
+ "$1+$1",
+ "2-$2",
+ "$3|3",
+ "$4^$4",
+ "1+\"hello\"",
+ "\"hello\"-2",
+ "3|\"hello\"^4",
+ };
+
+ const expected = [_]Parser.ExpressionError{
+ Parser.ExpressionError.IllegalOperationOnRegister,
+ Parser.ExpressionError.IllegalOperationOnRegister,
+ Parser.ExpressionError.IllegalOperationOnRegister,
+ Parser.ExpressionError.IllegalOperationOnRegister,
+ Parser.ExpressionError.BinaryOperationOnString,
+ Parser.ExpressionError.BinaryOperationOnString,
+ Parser.ExpressionError.BinaryOperationOnString,
+ };
+
+ for (0..test_cases.len) |i| {
+ var parser = try Parser.init(std.testing.allocator, test_cases[i]);
+ defer parser.deinit();
+ const symbol = parser.identifyExpression();
+ try std.testing.expectEqual(expected[i], symbol);
+ }
+}
diff --git a/src/temp.py b/src/temp.py
deleted file mode 100644
index 5577e9e..0000000
--- a/src/temp.py
+++ /dev/null
@@ -1,153 +0,0 @@
-x = [
- "TRAP",
- "FCMP",
- "FUN",
- "FEQL",
- "FADD",
- "FIX",
- "FSUB",
- "FIXU",
- "FLOT",
- "FLOTU",
- "SFLOT",
- "SFLOTU",
- "FMUL",
- "FCMPE",
- "FUNE",
- "FEQLE",
- "FDIV",
- "FSQRT",
- "FREM",
- "FINT",
- "MUL",
- "MULU",
- "DIV",
- "DIVU",
- "ADD",
- "ADDU",
- "SUB",
- "SUBU",
- "2ADDU",
- "4ADDU",
- "8ADDU",
- "16ADDU",
- "CMP",
- "CMPU",
- "NEG",
- "NEGU",
- "SL",
- "SLU",
- "SR",
- "SRU",
- "BN",
- "BZ",
- "BP",
- "BOD",
- "BNN",
- "BNZ",
- "BNP",
- "BEV",
- "PBN",
- "PBZ",
- "PBP",
- "PBOD",
- "PBNN",
- "PBNZ",
- "PBNP",
- "PBEV",
- "CSN",
- "CSZ",
- "CSP",
- "CSOD",
- "CSNN",
- "CSNZ",
- "CSNP",
- "CSEV",
- "ZSN",
- "ZSZ",
- "ZSP",
- "ZSOD",
- "ZSNN",
- "ZSNZ",
- "ZSNP",
- "ZSEV",
- "LDB",
- "LDBU",
- "LDW",
- "LDWU",
- "LDT",
- "LDTU",
- "LDO",
- "LDOU",
- "LDSF",
- "LDHT",
- "CSWAP",
- "LDUNC",
- "LDVTS",
- "PRELD",
- "PREGO",
- "GO",
- "STB",
- "STBU",
- "STW",
- "STWU",
- "STT",
- "STTU",
- "STO",
- "STOU",
- "STSF",
- "STHT",
- "STCO",
- "STUNC",
- "SYNCD",
- "PREST",
- "SYNCID",
- "PUSHGO",
- "OR",
- "ORN",
- "NOR",
- "XOR",
- "AND",
- "ANDN",
- "NAND",
- "NXOR",
- "BDIF",
- "WDIF",
- "TDIF",
- "ODIF",
- "MUX",
- "SADD",
- "MOR",
- "MXOR",
- "SETH",
- "SETMH",
- "SETML",
- "SETL",
- "INCH",
- "INCMH",
- "INCML",
- "INCL",
- "ORH",
- "ORMH",
- "ORML",
- "ORL",
- "ANDNH",
- "ANDNMH",
- "ANDNML",
- "ANDNL",
- "JMP",
- "PUSHJ",
- "GETA",
- "PUT",
- "POP",
- "RESUME",
- "SAVE",
- "UNSAVE",
- "SYNC",
- "SWYM",
- "GET",
- "TRIP",
-]
-
-for val in x:
- print(f"Operation{{.opcode = Opcode.{val}}},")