Archived
Compare commits
1
Commits
zig
..
55763b2155
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55763b2155 |
+15
-3
@@ -1,4 +1,16 @@
|
|||||||
zig-out/
|
# ---> Rust
|
||||||
zig-cache/
|
# Generated by Cargo
|
||||||
.vscode/
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
target/
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 0x4261756D
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
|
||||||
// declaratively construct a build graph that will be executed by an external
|
|
||||||
// runner.
|
|
||||||
pub fn build(b: *std.Build) void {
|
|
||||||
// Standard target options allows the person running `zig build` to choose
|
|
||||||
// what target to build for. Here we do not override the defaults, which
|
|
||||||
// means any target is allowed, and the default is native. Other options
|
|
||||||
// for restricting supported target set are available.
|
|
||||||
const target = b.standardTargetOptions(.{});
|
|
||||||
|
|
||||||
// Standard optimization options allow the person running `zig build` to select
|
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
|
||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "luaaaaah_zig",
|
|
||||||
// In this case the main source file is merely a path, however, in more
|
|
||||||
// complicated build scripts, this could be a generated file.
|
|
||||||
.root_source_file = .{ .path = "src/main.zig" },
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
exe.addModule("types", b.addModule("types", .{
|
|
||||||
.source_file = .{ .path = "src/types.zig" }
|
|
||||||
}));
|
|
||||||
exe.addModule("tokenizer", b.addModule("tokenizer", .{
|
|
||||||
.source_file = .{ .path = "src/tokenizer.zig" },
|
|
||||||
}));
|
|
||||||
exe.addModule("parser", b.addModule("parser", .{
|
|
||||||
.source_file = .{ .path = "src/parser.zig" },
|
|
||||||
}));
|
|
||||||
exe.addModule("treewalker", b.addModule("treewalker", .{
|
|
||||||
.source_file = .{ .path = "src/treewalker.zig" },
|
|
||||||
}));
|
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
|
||||||
// standard location when the user invokes the "install" step (the default
|
|
||||||
// step when running `zig build`).
|
|
||||||
b.installArtifact(exe);
|
|
||||||
|
|
||||||
// This *creates* a Run step in the build graph, to be executed when another
|
|
||||||
// step is evaluated that depends on it. The next line below will establish
|
|
||||||
// such a dependency.
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
|
|
||||||
// By making the run step depend on the install step, it will be run from the
|
|
||||||
// installation directory rather than directly from within the cache directory.
|
|
||||||
// This is not necessary, however, if the application depends on other installed
|
|
||||||
// files, this ensures they will be present and in the expected location.
|
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
|
||||||
|
|
||||||
// This allows the user to pass arguments to the application in the build
|
|
||||||
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
|
||||||
if (b.args) |args| {
|
|
||||||
run_cmd.addArgs(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This creates a build step. It will be visible in the `zig build --help` menu,
|
|
||||||
// and can be selected like this: `zig build run`
|
|
||||||
// This will evaluate the `run` step rather than the default, which is "install".
|
|
||||||
const run_step = b.step("run", "Run the app");
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
|
||||||
|
|
||||||
// Creates a step for unit testing. This only builds the test executable
|
|
||||||
// but does not run it.
|
|
||||||
const unit_tests = b.addTest(.{
|
|
||||||
.root_source_file = .{ .path = "src/main.zig" },
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
const run_unit_tests = b.addRunArtifact(unit_tests);
|
|
||||||
|
|
||||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
|
||||||
// the `zig build --help` menu, providing a way for the user to request
|
|
||||||
// running the unit tests.
|
|
||||||
const test_step = b.step("test", "Run unit tests");
|
|
||||||
test_step.dependOn(&run_unit_tests.step);
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const tokenize = @import("tokenizer.zig").tokenize;
|
|
||||||
const parse = @import("parser.zig").parse;
|
|
||||||
const treewalk = @import("treewalker.zig").interpret;
|
|
||||||
|
|
||||||
pub fn main() !void
|
|
||||||
{
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
||||||
defer _ = gpa.deinit();
|
|
||||||
const allocator = gpa.allocator();
|
|
||||||
|
|
||||||
const args = try std.process.argsAlloc(allocator);
|
|
||||||
defer std.process.argsFree(allocator, args);
|
|
||||||
const file = try std.fs.cwd().openFile(args[1], .{});
|
|
||||||
defer file.close();
|
|
||||||
const content = try file.readToEndAlloc(allocator, 13000);
|
|
||||||
defer allocator.free(content);
|
|
||||||
const tokens = try tokenize(content, allocator);
|
|
||||||
defer
|
|
||||||
{
|
|
||||||
var i: usize = 0;
|
|
||||||
while(i < tokens.len)
|
|
||||||
{
|
|
||||||
switch(tokens[i].tokenData)
|
|
||||||
{
|
|
||||||
.string => |*data|
|
|
||||||
{
|
|
||||||
allocator.free(data.*);
|
|
||||||
},
|
|
||||||
else => {}
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
allocator.free(tokens);
|
|
||||||
}
|
|
||||||
var parserAllocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
||||||
defer parserAllocator.deinit();
|
|
||||||
const root = try parse(tokens, &parserAllocator);
|
|
||||||
try treewalk(root, allocator);
|
|
||||||
}
|
|
||||||
-2572
@@ -1,2572 +0,0 @@
|
|||||||
const Token = @import("tokenizer.zig").Token;
|
|
||||||
const TokenType = @import("tokenizer.zig").TokenType;
|
|
||||||
const std = @import("std");
|
|
||||||
const types = @import("types.zig");
|
|
||||||
const CodeRegion = @import("types.zig").CodeRegion;
|
|
||||||
|
|
||||||
pub const ChunkNode = struct
|
|
||||||
{
|
|
||||||
block: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
pub fn dump(self: *const ChunkNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("ChunkNode ({} - {}):\n", .{self.startRegion, self.endRegion});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("block: ", .{});
|
|
||||||
self.block.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const BlockNode = struct
|
|
||||||
{
|
|
||||||
stats: std.ArrayList(StatNode),
|
|
||||||
retstat: ?RetstatNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const BlockNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("BlockNode:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("stats:\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.stats.items) |stat|
|
|
||||||
{
|
|
||||||
for (0..indent + 2) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
dumpStatNode(stat, indent + 2);
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("retstat: ", .{});
|
|
||||||
if(self.retstat == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.retstat.?.dump(indent + 1);
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const RetstatNode = struct
|
|
||||||
{
|
|
||||||
values: ?ExplistNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const RetstatNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Retstat Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("values: ", .{});
|
|
||||||
if(self.values == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.values.?.dump(indent + 1);
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const StatNode = union(enum)
|
|
||||||
{
|
|
||||||
Semicolon,
|
|
||||||
Assignment: AssignmentNode,
|
|
||||||
Functioncall: FunctioncallNode,
|
|
||||||
Label: []u8,
|
|
||||||
Break,
|
|
||||||
Goto: []u8,
|
|
||||||
Do: BlockNode,
|
|
||||||
While: WhileNode,
|
|
||||||
Repeat: RepeatNode,
|
|
||||||
If: IfNode,
|
|
||||||
ForNumerical: ForNumericalNode,
|
|
||||||
ForGeneric: ForGenericNode,
|
|
||||||
Function: FunctionNode,
|
|
||||||
LocalFunction: LocalFunctionNode,
|
|
||||||
Local: LocalNode,
|
|
||||||
};
|
|
||||||
fn dumpStatNode(stat: StatNode, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(stat)
|
|
||||||
{
|
|
||||||
.Semicolon => std.debug.print("Semicolon\n", .{}),
|
|
||||||
.Assignment => |*node| node.dump(indent),
|
|
||||||
.Functioncall => |*node| node.dump(indent),
|
|
||||||
.Label => |*label| std.debug.print("Label: '{s}'\n", .{label.*}),
|
|
||||||
.Break => std.debug.print("Break\n", .{}),
|
|
||||||
.Goto => |*label| std.debug.print("Goto: '{s}'\n", .{label.*}),
|
|
||||||
.Do => |*node| node.dump(indent),
|
|
||||||
.While => |*node| node.dump(indent),
|
|
||||||
.Repeat => |*node| node.dump(indent),
|
|
||||||
.If => |*node| node.dump(indent),
|
|
||||||
.ForNumerical => |*node| node.dump(indent),
|
|
||||||
.ForGeneric => |*node| node.dump(indent),
|
|
||||||
.Function => |*node| node.dump(indent),
|
|
||||||
.LocalFunction => |*node| node.dump(indent),
|
|
||||||
.Local => |*node| node.dump(indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const AssignmentNode = struct
|
|
||||||
{
|
|
||||||
lhs: VarlistNode, rhs: ExplistNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const AssignmentNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Assignment Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("lhs: ", .{});
|
|
||||||
self.lhs.dump(indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("rhs: ", .{});
|
|
||||||
self.rhs.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const WhileNode = struct
|
|
||||||
{
|
|
||||||
condition: ExpNode,
|
|
||||||
body: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const WhileNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("While Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("condition: ", .{});
|
|
||||||
dumpExpNode(self.condition, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const RepeatNode = struct
|
|
||||||
{
|
|
||||||
condition: ExpNode,
|
|
||||||
body: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const RepeatNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Repeat Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("condition: ", .{});
|
|
||||||
dumpExpNode(self.condition, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const IfNode = struct
|
|
||||||
{
|
|
||||||
condition: ExpNode,
|
|
||||||
body: BlockNode,
|
|
||||||
elseifs: std.ArrayList(ElseifNode),
|
|
||||||
else_: ?BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const IfNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("If Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("condition: ", .{});
|
|
||||||
dumpExpNode(self.condition, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("elseifs:\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.elseifs.items) |elseif|
|
|
||||||
{
|
|
||||||
for (0..indent + 2) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
elseif.dump(indent + 2);
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("else: ", .{});
|
|
||||||
if(self.else_ == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.else_.?.dump(indent + 1);
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const ForNumericalNode = struct
|
|
||||||
{
|
|
||||||
variable: []u8,
|
|
||||||
start: ExpNode,
|
|
||||||
end: ExpNode,
|
|
||||||
change: ?ExpNode,
|
|
||||||
body: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const ForNumericalNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("For Numerical Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("variable: '{s}'\n", .{self.variable});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("start: ", .{});
|
|
||||||
dumpExpNode(self.start, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("end: ", .{});
|
|
||||||
dumpExpNode(self.end, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("change: ", .{});
|
|
||||||
if(self.change == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dumpExpNode(self.start, indent + 1);
|
|
||||||
}
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const ForGenericNode = struct
|
|
||||||
{
|
|
||||||
vars: std.ArrayList([]u8),
|
|
||||||
exps: ExplistNode,
|
|
||||||
body: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const ForGenericNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("For Generic Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("vars:\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.vars.items) |v|
|
|
||||||
{
|
|
||||||
for (0..(indent + 2)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("'{s}'\n", .{v});
|
|
||||||
}
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
std.debug.print("exps: ", .{});
|
|
||||||
self.exps.dump(indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const FunctionNode = struct
|
|
||||||
{
|
|
||||||
name: FuncnameNode,
|
|
||||||
body: FuncbodyNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const FunctionNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Function Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("name: ", .{});
|
|
||||||
self.name.dump(indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const LocalFunctionNode = struct
|
|
||||||
{
|
|
||||||
name: []u8,
|
|
||||||
body: FuncbodyNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const LocalFunctionNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Local Function Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("name: '{s}'\n", .{self.name});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
pub const LocalNode = struct
|
|
||||||
{
|
|
||||||
attnames: AttnamelistNode,
|
|
||||||
values: ?ExplistNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const LocalNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Local Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("attnames: ", .{});
|
|
||||||
self.attnames.dump(indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("values: ", .{});
|
|
||||||
if(self.values == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.values.?.dump(indent + 1);
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const FunctioncallNode = struct
|
|
||||||
{
|
|
||||||
function: SuffixexpNode,
|
|
||||||
objectArg: ?[]u8,
|
|
||||||
args: ArgsNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const FunctioncallNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Functioncall Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("function: ", .{});
|
|
||||||
dumpSuffixExpNode(self.function, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("object arg: ", .{});
|
|
||||||
if(self.objectArg == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std.debug.print("'{s}'\n", .{self.objectArg.?});
|
|
||||||
}
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("args: ", .{});
|
|
||||||
dumpArgsNode(self.args, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const VarlistNode = struct
|
|
||||||
{
|
|
||||||
vars: std.ArrayList(VarNode),
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const VarlistNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Varlist Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("vars:\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.vars.items) |item|
|
|
||||||
{
|
|
||||||
for (0..indent + 2) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
dumpVarNode(item, indent + 2);
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const ExplistNode = struct
|
|
||||||
{
|
|
||||||
exps: std.ArrayList(ExpNode),
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const ExplistNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Explist Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("exps:\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.exps.items) |item|
|
|
||||||
{
|
|
||||||
for (0..indent + 2) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
dumpExpNode(item, indent + 2);
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const ExpNode = union(enum)
|
|
||||||
{
|
|
||||||
Nil,
|
|
||||||
False,
|
|
||||||
True,
|
|
||||||
Numeral: types.Numeral,
|
|
||||||
LiteralString: []u8,
|
|
||||||
Varargs,
|
|
||||||
Functiondef: FuncbodyNode,
|
|
||||||
Suffixexp: *SuffixexpNode,
|
|
||||||
Tableconstructor: TableconstructorNode,
|
|
||||||
Unop: UnopNode,
|
|
||||||
Binop: *BinopNode,
|
|
||||||
};
|
|
||||||
fn dumpExpNode(expNode: ExpNode, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(expNode)
|
|
||||||
{
|
|
||||||
.Nil => std.debug.print("Nil\n", .{}),
|
|
||||||
.False => std.debug.print("False\n", .{}),
|
|
||||||
.True => std.debug.print("True\n", .{}),
|
|
||||||
.Numeral => |*numeral| std.debug.print("{}\n", .{numeral.*}),
|
|
||||||
.LiteralString => |*string| std.debug.print("LiteralString: '{s}'\n", .{string.*}),
|
|
||||||
.Varargs => std.debug.print("Varargs", .{}),
|
|
||||||
.Functiondef => |*node| node.dump(indent),
|
|
||||||
.Suffixexp => |*node| dumpSuffixExpNode(node.*.*, indent),
|
|
||||||
.Tableconstructor => |*node| node.dump(indent),
|
|
||||||
.Unop => |*node| node.dump(indent),
|
|
||||||
.Binop => |*node| node.*.dump(indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const UnopNode = struct
|
|
||||||
{
|
|
||||||
unopType: UnopType,
|
|
||||||
exp: *ExpNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const UnopNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Unop Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("unop type: {}\n", .{self.unopType});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("exp: ", .{});
|
|
||||||
dumpExpNode(self.exp.*, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const BinopNode = struct
|
|
||||||
{
|
|
||||||
lhs: ExpNode,
|
|
||||||
op: BinopType,
|
|
||||||
rhs: ExpNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const BinopNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Binop Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("lhs: ", .{});
|
|
||||||
dumpExpNode(self.lhs, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("op: {}\n", .{self.op});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("rhs: ", .{});
|
|
||||||
dumpExpNode(self.rhs, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const ElseifNode = struct
|
|
||||||
{
|
|
||||||
condition: ExpNode,
|
|
||||||
body: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const ElseifNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Elseif Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("condition: ", .{});
|
|
||||||
dumpExpNode(self.condition, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("body: ", .{});
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const FuncnameNode = struct
|
|
||||||
{
|
|
||||||
name: []u8,
|
|
||||||
dottedNames: std.ArrayList([]u8),
|
|
||||||
firstArg: ?[]u8,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const FuncnameNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Funcname Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("name: '{s}'\n", .{self.name});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("dottedNames:\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.dottedNames.items) |dottedName|
|
|
||||||
{
|
|
||||||
for (0..(indent + 2)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("'{s}'\n", .{dottedName});
|
|
||||||
}
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("firstArg: ", .{});
|
|
||||||
if(self.firstArg == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std.debug.print("'{s}'\n", .{self.firstArg.?});
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
pub const FuncbodyNode = struct
|
|
||||||
{
|
|
||||||
pars: ?ParlistNode,
|
|
||||||
body: BlockNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const FuncbodyNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Funcbody Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("pars: ", .{});
|
|
||||||
if(self.pars == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.pars.?.dump(indent + 1);
|
|
||||||
}
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
self.body.dump(indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const AttnamelistNode = struct
|
|
||||||
{
|
|
||||||
attnames: std.ArrayList(AttnameNode),
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const AttnamelistNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Attnamelist Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("attNames:\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.attnames.items) |attNames|
|
|
||||||
{
|
|
||||||
for (0..(indent + 2)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
attNames.dump(indent + 2);
|
|
||||||
}
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const AttnameNode = struct
|
|
||||||
{
|
|
||||||
name: []u8,
|
|
||||||
attribute: ?[]u8,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const AttnameNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Funcname Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("name: '{s}'\n", .{self.name});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("attribute: ", .{});
|
|
||||||
if(self.attribute == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std.debug.print("'{s}'\n", .{self.attribute.?});
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const SuffixexpNode = union(enum)
|
|
||||||
{
|
|
||||||
Normal: NormalSuffixNode,
|
|
||||||
Functioncall: *FunctioncallNode,
|
|
||||||
};
|
|
||||||
fn dumpSuffixExpNode(suffixexpNode: SuffixexpNode, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(suffixexpNode)
|
|
||||||
{
|
|
||||||
.Normal => |*node| node.dump(indent),
|
|
||||||
.Functioncall => |*node| node.*.dump(indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const ArgsNode = union(enum)
|
|
||||||
{
|
|
||||||
Bracketed: ?ExplistNode,
|
|
||||||
Tableconstructor: TableconstructorNode,
|
|
||||||
Literal: []u8,
|
|
||||||
};
|
|
||||||
fn dumpArgsNode(argsNode: ArgsNode, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(argsNode)
|
|
||||||
{
|
|
||||||
.Bracketed => |*name|
|
|
||||||
{
|
|
||||||
if(name.* == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name.*.?.dump(indent);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Tableconstructor => |*node| node.dump(indent),
|
|
||||||
.Literal => |*string| std.debug.print("Literal: '{s}'\n", .{string}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const VarNode = union(enum)
|
|
||||||
{
|
|
||||||
Name: []u8,
|
|
||||||
Indexed: IndexedVarNode,
|
|
||||||
Member: MemberVarNode,
|
|
||||||
};
|
|
||||||
fn dumpVarNode(varNode: VarNode, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(varNode)
|
|
||||||
{
|
|
||||||
.Name => |*name| std.debug.print("Name: '{s}'\n", .{name.*}),
|
|
||||||
.Indexed => |*node| node.dump(indent),
|
|
||||||
.Member => |*node| node.dump(indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const IndexedVarNode = struct
|
|
||||||
{
|
|
||||||
value: SuffixexpNode,
|
|
||||||
index: ExpNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const IndexedVarNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Indexed Var Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("value: ", .{});
|
|
||||||
dumpSuffixExpNode(self.value, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("index: ", .{});
|
|
||||||
dumpExpNode(self.index, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const MemberVarNode = struct
|
|
||||||
{
|
|
||||||
value: SuffixexpNode,
|
|
||||||
name: []u8,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const MemberVarNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Member Var Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("value: ", .{});
|
|
||||||
dumpSuffixExpNode(self.value, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("name: '{s}'\n", .{self.name});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
pub const TableconstructorNode = struct
|
|
||||||
{
|
|
||||||
exps: ?FieldlistNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const TableconstructorNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Tableconstructor Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("exps: ", .{});
|
|
||||||
if(self.exps == null)
|
|
||||||
{
|
|
||||||
std.debug.print("null\n", .{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.exps.?.dump(indent + 1);
|
|
||||||
}
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const UnopType = enum
|
|
||||||
{
|
|
||||||
Minus, LogicalNot, Length, BinaryNot,
|
|
||||||
};
|
|
||||||
pub const BinopType = enum
|
|
||||||
{
|
|
||||||
LogicalOr,
|
|
||||||
LocicalAnd,
|
|
||||||
Lt, Gt, LtEquals, GtEquals, NotEquals, Equals,
|
|
||||||
BinaryOr,
|
|
||||||
BinaryNot,
|
|
||||||
BinaryAnd,
|
|
||||||
Shl, Shr,
|
|
||||||
Concat,
|
|
||||||
Add, Sub,
|
|
||||||
Mul, Div, IntDiv, Mod,
|
|
||||||
Exp,
|
|
||||||
};
|
|
||||||
pub const ParlistNode = struct
|
|
||||||
{
|
|
||||||
names: std.ArrayList([]u8),
|
|
||||||
hasVarargs: bool,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const ParlistNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Parlist Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("names:\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.names.items) |name|
|
|
||||||
{
|
|
||||||
for (0..indent + 2) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("'{s}'\n", .{name});
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("has Varargs: {}\n", .{self.hasVarargs});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const NormalSuffixNode = struct
|
|
||||||
{
|
|
||||||
firstPart: SuffixexpFirstPart,
|
|
||||||
suffixes: std.ArrayList(SuffixexpSuffix),
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const NormalSuffixNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Normal Suffix Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("First Part: ", .{});
|
|
||||||
dumpSuffixExpFirstPart(self.firstPart, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("Suffixes:\n", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.suffixes.items) |suffix|
|
|
||||||
{
|
|
||||||
for (0..(indent + 2)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
dumpSuffixSuffix(suffix, indent + 2);
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const SuffixexpFirstPart = union(enum)
|
|
||||||
{
|
|
||||||
Name: []u8,
|
|
||||||
BracketedExpr: ExpNode,
|
|
||||||
};
|
|
||||||
fn dumpSuffixExpFirstPart(suffixexpFirstPart: SuffixexpFirstPart, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(suffixexpFirstPart)
|
|
||||||
{
|
|
||||||
.Name => |*name| std.debug.print("Name: '{s}'\n", .{name.*}),
|
|
||||||
.BracketedExpr => |*node| dumpExpNode(node.*, indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const SuffixexpSuffix = union(enum)
|
|
||||||
{
|
|
||||||
Dot: []u8,
|
|
||||||
Indexed: ExpNode,
|
|
||||||
Args: ArgsNode,
|
|
||||||
ArgsFirstArg: ArgsFirstArgNode,
|
|
||||||
};
|
|
||||||
fn dumpSuffixSuffix(suffixexpSuffix: SuffixexpSuffix, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(suffixexpSuffix)
|
|
||||||
{
|
|
||||||
.Dot => |*name| std.debug.print("Dot: '{s}'\n", .{name.*}),
|
|
||||||
.Indexed => |*node| dumpExpNode(node.*, indent),
|
|
||||||
.Args => |*node| dumpArgsNode(node.*, indent),
|
|
||||||
.ArgsFirstArg => |*node| node.dump(indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ArgsFirstArgNode = struct
|
|
||||||
{
|
|
||||||
name: []u8,
|
|
||||||
rest: ArgsNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const ArgsFirstArgNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Args First Arg Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("name: '{s}'\n", .{self.name});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("rest: ", .{});
|
|
||||||
dumpArgsNode(self.rest, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
pub const FieldlistNode = struct
|
|
||||||
{
|
|
||||||
exps: std.ArrayList(FieldNode),
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const FieldlistNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Fieldlist Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("exps: ", .{});
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("[\n", .{});
|
|
||||||
for(self.exps.items) |exp|
|
|
||||||
{
|
|
||||||
for (0..(indent + 2)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
dumpFieldNode(exp, indent + 2);
|
|
||||||
}
|
|
||||||
for (0..indent + 1) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("]\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub const FieldNode = union(enum)
|
|
||||||
{
|
|
||||||
IndexedAssignment: IndexedAssignmentNode,
|
|
||||||
Assignment: FieldAssignmentNode,
|
|
||||||
Exp: ExpNode,
|
|
||||||
};
|
|
||||||
pub const FieldAssignmentNode = struct
|
|
||||||
{
|
|
||||||
lhs: []u8,
|
|
||||||
rhs: ExpNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const FieldAssignmentNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Field Assignment Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("lhs: {s}\n", .{self.lhs});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("rhs: ", .{});
|
|
||||||
dumpExpNode(self.rhs, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fn dumpFieldNode(fieldNode: FieldNode, indent: usize) void
|
|
||||||
{
|
|
||||||
switch(fieldNode)
|
|
||||||
{
|
|
||||||
.IndexedAssignment => |*node| node.dump(indent),
|
|
||||||
.Assignment => |*node| node.dump(indent),
|
|
||||||
.Exp => |*node| dumpExpNode(node.*, indent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const IndexedAssignmentNode = struct
|
|
||||||
{
|
|
||||||
index: ExpNode,
|
|
||||||
rhs: ExpNode,
|
|
||||||
startRegion: CodeRegion,
|
|
||||||
endRegion: CodeRegion,
|
|
||||||
|
|
||||||
fn dump(self: *const IndexedAssignmentNode, indent: usize) void
|
|
||||||
{
|
|
||||||
std.debug.print("Indexed Assignment Node:\n", .{});
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("{{\n", .{});
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("index: ", .{});
|
|
||||||
dumpExpNode(self.index, indent + 1);
|
|
||||||
for (0..(indent + 1)) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("rhs: ", .{});
|
|
||||||
dumpExpNode(self.rhs, indent + 1);
|
|
||||||
for (0..indent) |_|
|
|
||||||
{
|
|
||||||
std.debug.print("\t", .{});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn parse(tokens: []Token, allocator: *std.heap.ArenaAllocator) !ChunkNode
|
|
||||||
{
|
|
||||||
var i: usize = 0;
|
|
||||||
const maybeParsedChunk = parseChunk(tokens, &i, allocator) catch |err|
|
|
||||||
{
|
|
||||||
//std.debug.print("{any}: data: {any}, type: {any}\n", .{tokens[i].region, tokens[i].tokenData, tokens[i].tokenType});
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
return maybeParsedChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ParserError = error
|
|
||||||
{
|
|
||||||
NotImplemented,
|
|
||||||
ReachedEOFParsing,
|
|
||||||
ReachedEOFExpectedNameForGoto,
|
|
||||||
ExpectedNameForGoto,
|
|
||||||
MissingEndForDoBlock,
|
|
||||||
MissingDoAfterWhileCondition,
|
|
||||||
MissingEndForWhileBody,
|
|
||||||
ExpectedUntilAfterRepeatBody,
|
|
||||||
ExpectedThenAfterIfCondition,
|
|
||||||
ReachedEOFAfterIfBody,
|
|
||||||
ExpectedThenAfterElseifCondition,
|
|
||||||
ReachedEOFAfterElseifs,
|
|
||||||
ExpectedEndClosingIf,
|
|
||||||
ExpectedNameAfterFor,
|
|
||||||
ExpectedCommaAfterForEqStartValue,
|
|
||||||
ReachedEOFAfterForEqEndValue,
|
|
||||||
ExpectedDoAfterForEqHead,
|
|
||||||
ExpectedAnotherNameInForInNamelist,
|
|
||||||
ReachedEOFAfterNameInForInNamelist,
|
|
||||||
ExpectedInAfterForInNamelist,
|
|
||||||
ExpectedDoAfterForInExplist,
|
|
||||||
ExpectedEndAfterForInBody,
|
|
||||||
ExpectedEndAfterForEqBody,
|
|
||||||
UnexpectedTokenAfterFirstNameInFor,
|
|
||||||
ReachedEOFInLocal,
|
|
||||||
ExpectedLocalFunctionName,
|
|
||||||
ExpectedNameAfterDoubleColonInLabelDeclaration,
|
|
||||||
ExpectedDoubleColonAfterNameInLabelDeclaration,
|
|
||||||
ExpectedFunctioncall,
|
|
||||||
ExpectedEqAfterAssignmentVarList,
|
|
||||||
ReachedEOFInSuffixExp,
|
|
||||||
ExpectedRoundClosedClosingBracketedPrimaryExp,
|
|
||||||
UnexpectedTokenAsFirstPartOfSuffixExp,
|
|
||||||
ExpectedNameInDottedSuffixExp,
|
|
||||||
ExpectedSquareClosedClosingIndexedSuffixExp,
|
|
||||||
ExpectedNameInArgsFirstArgSuffixExp,
|
|
||||||
ExpectedDotOrIndexedSuffixWhenConvertingSuffixExpToVar,
|
|
||||||
ReachedEOFExpectedPrimaryExpression,
|
|
||||||
ReachedEOFInArgs,
|
|
||||||
ReachedEOFInBracketedArgs,
|
|
||||||
ExpectedRoundClosedClosingBracketedArgs,
|
|
||||||
UnexpectedTokenInArgs,
|
|
||||||
NoPrecedenceForOperator,
|
|
||||||
NoBinopTypeForOperator,
|
|
||||||
ExpectednameInAttribName,
|
|
||||||
ExpectedAttributeInAttrib,
|
|
||||||
ExpectedGtInAttrib,
|
|
||||||
ExpectedFuncname,
|
|
||||||
ExpectedNameInDottedFuncname,
|
|
||||||
ExpectedNameOfFirstArgInFuncname,
|
|
||||||
ExpectedRoundOpenStartingFuncbody,
|
|
||||||
ReachedEOFInFuncbodyParlist,
|
|
||||||
ExpectedRoundClosedClosingFuncbodyParlist,
|
|
||||||
ExpectedEndClosingFuncbody,
|
|
||||||
ReachedEOFInParlist,
|
|
||||||
ExpectedNameStartingParlist,
|
|
||||||
ReachedEOFInParlistNameList,
|
|
||||||
UnexpectedTokenInParlistNameList,
|
|
||||||
ExpectedReturnStartingRetstat,
|
|
||||||
ExpectedCurlyOpenOpeningTableconstructor,
|
|
||||||
ExpectedCurlyClosedClosingTableconstructor,
|
|
||||||
ReachedEOFInField,
|
|
||||||
ExpectedSquareClosedClosingIndexedField,
|
|
||||||
ExpectedEqualsInIndexedFieldExpression,
|
|
||||||
OutOfMemory,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn parseChunk(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !ChunkNode
|
|
||||||
{
|
|
||||||
const block = try parseBlock(tokens, i, allocator);
|
|
||||||
return ChunkNode { .block = block, .startRegion = block.startRegion, .endRegion = block.endRegion };
|
|
||||||
}
|
|
||||||
fn parseBlock(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) ParserError!BlockNode
|
|
||||||
{
|
|
||||||
var ret = BlockNode { .stats = std.ArrayList(StatNode).init(allocator.*.allocator()), .retstat = null, .startRegion = tokens[i.*].region, .endRegion = tokens[i.*].region };
|
|
||||||
while(i.* < tokens.len and
|
|
||||||
tokens[i.*].tokenType != TokenType.Return and
|
|
||||||
tokens[i.*].tokenType != TokenType.End and
|
|
||||||
tokens[i.*].tokenType != TokenType.Elseif and
|
|
||||||
tokens[i.*].tokenType != TokenType.Else
|
|
||||||
)
|
|
||||||
{
|
|
||||||
try ret.stats.append(try parseStat(tokens, i, allocator));
|
|
||||||
}
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Return)
|
|
||||||
{
|
|
||||||
ret.retstat = try parseRetstat(tokens, i, allocator);
|
|
||||||
}
|
|
||||||
ret.endRegion = if(i.* - 1 < tokens.len) tokens[i.* - 1].region else tokens[tokens.len - 1].region;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseStat(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !StatNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFParsing;
|
|
||||||
}
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Semicolon =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode.Semicolon;
|
|
||||||
},
|
|
||||||
TokenType.Break =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode.Break;
|
|
||||||
},
|
|
||||||
TokenType.Goto =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFExpectedNameForGoto;
|
|
||||||
}
|
|
||||||
if(tokens[i.*].tokenType == TokenType.Name)
|
|
||||||
{
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .Goto = name };
|
|
||||||
}
|
|
||||||
return error.ExpectedNameForGoto;
|
|
||||||
},
|
|
||||||
TokenType.Do =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.MissingEndForDoBlock;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .Do = body };
|
|
||||||
},
|
|
||||||
TokenType.While =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
const condition = try parseExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Do)
|
|
||||||
{
|
|
||||||
return error.MissingDoAfterWhileCondition;
|
|
||||||
}
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.MissingEndForWhileBody;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .While = WhileNode { .body = body, .condition = condition, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Repeat =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Until)
|
|
||||||
{
|
|
||||||
return error.ExpectedUntilAfterRepeatBody;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .Repeat = RepeatNode { .body = body, .condition = try parseExp(tokens, i, allocator), .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.If =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
const condition = try parseExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Then)
|
|
||||||
{
|
|
||||||
return error.ExpectedThenAfterIfCondition;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFAfterIfBody;
|
|
||||||
}
|
|
||||||
var ifNode = IfNode { .body = body, .condition = condition, .elseifs = std.ArrayList(ElseifNode).init(allocator.*.allocator()), .else_ = null, .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
while(tokens[i.*].tokenType == TokenType.Elseif)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const elseifCondition = try parseExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Then)
|
|
||||||
{
|
|
||||||
return error.ExpectedThenAfterElseifCondition;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
try ifNode.elseifs.append(ElseifNode { .body = try parseBlock(tokens, i, allocator), .condition = elseifCondition, .startRegion = startRegion, .endRegion = endRegion });
|
|
||||||
}
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFAfterElseifs;
|
|
||||||
}
|
|
||||||
if(tokens[i.*].tokenType == TokenType.Else)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
ifNode.else_ = try parseBlock(tokens, i, allocator);
|
|
||||||
}
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.ExpectedEndClosingIf;
|
|
||||||
}
|
|
||||||
ifNode.endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .If = ifNode };
|
|
||||||
},
|
|
||||||
TokenType.For =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameAfterFor;
|
|
||||||
}
|
|
||||||
const variable = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Equals =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const start = try parseExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Comma)
|
|
||||||
{
|
|
||||||
return error.ExpectedCommaAfterForEqStartValue;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
const end = try parseExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFAfterForEqEndValue;
|
|
||||||
}
|
|
||||||
var change: ?ExpNode = null;
|
|
||||||
if(tokens[i.*].tokenType == TokenType.Comma)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
change = try parseExp(tokens, i, allocator);
|
|
||||||
}
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Do)
|
|
||||||
{
|
|
||||||
return error.ExpectedDoAfterForEqHead;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.ExpectedEndAfterForEqBody;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .ForNumerical = ForNumericalNode { .variable = variable, .start = start, .end = end, .change = change, .body = body, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Comma =>
|
|
||||||
{
|
|
||||||
var names = std.ArrayList([]u8).init(allocator.*.allocator());
|
|
||||||
try names.append(variable);
|
|
||||||
while(tokens[i.*].tokenType == TokenType.Comma)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedAnotherNameInForInNamelist;
|
|
||||||
}
|
|
||||||
try names.append(tokens[i.*].tokenData.string);
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFAfterNameInForInNamelist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.In)
|
|
||||||
{
|
|
||||||
return error.ExpectedInAfterForInNamelist;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
const exps = try parseExplist(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Do)
|
|
||||||
{
|
|
||||||
return error.ExpectedDoAfterForInExplist;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.ExpectedEndAfterForInBody;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .ForGeneric = ForGenericNode { .vars = names, .exps = exps, .body = body, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.In =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const exps = try parseExplist(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Do)
|
|
||||||
{
|
|
||||||
return error.ExpectedDoAfterForInExplist;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
const body = try parseBlock(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.ExpectedEndAfterForInBody;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
var names = try std.ArrayList([]u8).initCapacity(allocator.allocator(), 1);
|
|
||||||
try names.insert(0, variable);
|
|
||||||
return StatNode { .ForGeneric = ForGenericNode { .vars = names, .exps = exps, .body = body, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
else => return error.UnexpectedTokenAfterFirstNameInFor,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenType.Function =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
const name = try parseFuncname(tokens, i, allocator);
|
|
||||||
const body = try parseFuncbody(tokens, i, allocator);
|
|
||||||
return StatNode { .Function = FunctionNode { .name = name, .body = body, .startRegion = startRegion, .endRegion = body.endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Local =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInLocal;
|
|
||||||
}
|
|
||||||
if(tokens[i.*].tokenType == TokenType.Function)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedLocalFunctionName;
|
|
||||||
}
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .LocalFunction = LocalFunctionNode { .name = name, .body = try parseFuncbody(tokens, i, allocator), .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var ret = LocalNode { .attnames = try parseAttnamelist(tokens, i, allocator), .values = null, .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Equals)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
ret.values = try parseExplist(tokens, i, allocator);
|
|
||||||
ret.endRegion = ret.values.?.endRegion;
|
|
||||||
}
|
|
||||||
return StatNode { .Local = ret };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenType.ColonColon =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameAfterDoubleColonInLabelDeclaration;
|
|
||||||
}
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.ColonColon)
|
|
||||||
{
|
|
||||||
return error.ExpectedDoubleColonAfterNameInLabelDeclaration;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
return StatNode { .Label = name };
|
|
||||||
},
|
|
||||||
TokenType.Name, TokenType.RoundOpen =>
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
const suffixExp = try parseSuffixExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
switch(suffixExp)
|
|
||||||
{
|
|
||||||
.Normal => return error.ExpectedFunctioncall,
|
|
||||||
.Functioncall => |functioncall| return StatNode { .Functioncall = functioncall.* },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Equals =>
|
|
||||||
{
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
var lhs = std.ArrayList(VarNode).init(allocator.allocator());
|
|
||||||
try lhs.append(try suffixExpToVar(suffixExp, startRegion, endRegion));
|
|
||||||
const rhs = try parseExplist(tokens, i, allocator);
|
|
||||||
return StatNode { .Assignment = AssignmentNode { .lhs = VarlistNode { .vars = lhs, .startRegion = endRegion, .endRegion = tokens[@min(i.*, tokens.len) - 1].region }, .rhs = rhs, .startRegion = startRegion, .endRegion = rhs.endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Comma =>
|
|
||||||
{
|
|
||||||
var varlistNode = VarlistNode { .vars = std.ArrayList(VarNode).init(allocator.allocator()), .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
try varlistNode.vars.append(try suffixExpToVar(suffixExp, startRegion, tokens[@min(i.*, tokens.len) - 1].region));
|
|
||||||
while(tokens[i.*].tokenType == TokenType.Comma)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
try varlistNode.vars.append(try parseVar(tokens, i, allocator));
|
|
||||||
}
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Equals)
|
|
||||||
{
|
|
||||||
return error.ExpectedEqAfterAssignmentVarList;
|
|
||||||
}
|
|
||||||
varlistNode.endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
const rhs = try parseExplist(tokens, i, allocator);
|
|
||||||
return StatNode { .Assignment = AssignmentNode { .lhs = varlistNode, .rhs = rhs, .startRegion = startRegion, .endRegion = rhs.endRegion } };
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
switch(suffixExp)
|
|
||||||
{
|
|
||||||
.Normal => return error.ExpectedFunctioncall,
|
|
||||||
.Functioncall => |functioncall| return StatNode { .Functioncall = functioncall.* },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
std.debug.print("{}\n", .{tokens[i.*]});
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn parseRetstat(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !RetstatNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Return)
|
|
||||||
{
|
|
||||||
return error.ExpectedReturnStartingRetstat;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or
|
|
||||||
tokens[i.*].tokenType == TokenType.Semicolon or tokens[i.*].tokenType == TokenType.Else or tokens[i.*].tokenType == TokenType.Elseif or tokens[i.*].tokenType == TokenType.End)
|
|
||||||
{
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Semicolon)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
}
|
|
||||||
return RetstatNode { .values = null, .startRegion = startRegion, .endRegion = tokens[@min(i.*, tokens.len) - 1].region };
|
|
||||||
}
|
|
||||||
const values = try parseExplist(tokens, i, allocator);
|
|
||||||
var endRegion = values.endRegion;
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Semicolon)
|
|
||||||
{
|
|
||||||
endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
}
|
|
||||||
return RetstatNode { .values = values, .startRegion = startRegion, .endRegion = endRegion };
|
|
||||||
}
|
|
||||||
fn parseExp(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) ParserError!ExpNode
|
|
||||||
{
|
|
||||||
const lhs = try parseExpPrimary(tokens, i, allocator);
|
|
||||||
return parseExpPrecedence(tokens, i, allocator, lhs, 0);
|
|
||||||
}
|
|
||||||
fn parseExpPrimary(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !ExpNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFExpectedPrimaryExpression;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Nil =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode.Nil;
|
|
||||||
},
|
|
||||||
TokenType.True =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode.True;
|
|
||||||
},
|
|
||||||
TokenType.False =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode.False;
|
|
||||||
},
|
|
||||||
TokenType.Numeral =>
|
|
||||||
{
|
|
||||||
const numeral = tokens[i.*].tokenData.numeral;
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode { .Numeral = numeral };
|
|
||||||
},
|
|
||||||
TokenType.StringLiteral =>
|
|
||||||
{
|
|
||||||
const string = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode { .LiteralString = string };
|
|
||||||
},
|
|
||||||
TokenType.DotDotDot =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode.Varargs;
|
|
||||||
},
|
|
||||||
TokenType.Function =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return ExpNode { .Functiondef = try parseFuncbody(tokens, i, allocator) };
|
|
||||||
},
|
|
||||||
TokenType.CurlyOpen => return ExpNode { .Tableconstructor = try parseTableconstructor(tokens, i, allocator) },
|
|
||||||
TokenType.Minus =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const unop = try allocator.allocator().create(ExpNode);
|
|
||||||
unop.* = try parseExp(tokens, i, allocator);
|
|
||||||
const endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ExpNode { .Unop = UnopNode { .unopType = UnopType.Minus, .exp = unop, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Hash =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const unop = try allocator.allocator().create(ExpNode);
|
|
||||||
unop.* = try parseExp(tokens, i, allocator);
|
|
||||||
const endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ExpNode { .Unop = UnopNode { .unopType = UnopType.Length, .exp = unop, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Not =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const unop = try allocator.allocator().create(ExpNode);
|
|
||||||
unop.* = try parseExp(tokens, i, allocator);
|
|
||||||
const endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ExpNode { .Unop = UnopNode { .unopType = UnopType.LogicalNot, .exp = unop, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Tilde =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const unop = try allocator.allocator().create(ExpNode);
|
|
||||||
unop.* = try parseExp(tokens, i, allocator);
|
|
||||||
const endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ExpNode { .Unop = UnopNode { .unopType = UnopType.BinaryNot, .exp = unop, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
const suffixexp = try allocator.allocator().create(SuffixexpNode);
|
|
||||||
suffixexp.* = try parseSuffixExp(tokens, i, allocator);
|
|
||||||
return ExpNode { .Suffixexp = suffixexp };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn parseExpPrecedence(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator, lhs: ExpNode, minPrecedence: u8) !ExpNode
|
|
||||||
{
|
|
||||||
var currentLhs = lhs;
|
|
||||||
while(i.* < tokens.len and isBinop(tokens[i.*]))
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
const precedence = try getPrecedence(tokens[i.*]);
|
|
||||||
if(precedence < minPrecedence)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const op = try getBinopType(tokens[i.*]);
|
|
||||||
i.* += 1;
|
|
||||||
var rhs = try parseExpPrimary(tokens, i, allocator);
|
|
||||||
while(i.* < tokens.len and isBinop(tokens[i.*]) and
|
|
||||||
(try getPrecedence(tokens[i.*]) > precedence or
|
|
||||||
(try getPrecedence(tokens[i.*]) == precedence and isRightAssociative(tokens[i.*]))))
|
|
||||||
{
|
|
||||||
const associativityBoost: u8 = if(try getPrecedence(tokens[i.*]) == precedence) 0 else 1;
|
|
||||||
rhs = try parseExpPrecedence(tokens, i, allocator, rhs, precedence + associativityBoost);
|
|
||||||
}
|
|
||||||
const binop = try allocator.allocator().create(BinopNode);
|
|
||||||
binop.* = BinopNode { .lhs = currentLhs, .op = op, .rhs = rhs, .startRegion = startRegion, .endRegion = tokens[@min(i.*, tokens.len) - 1].region };
|
|
||||||
currentLhs = ExpNode { .Binop = binop };
|
|
||||||
}
|
|
||||||
return currentLhs;
|
|
||||||
}
|
|
||||||
fn isRightAssociative(token: Token) bool
|
|
||||||
{
|
|
||||||
return token.tokenType == TokenType.DotDot or token.tokenType == TokenType.Caret;
|
|
||||||
}
|
|
||||||
fn getBinopType(token: Token) !BinopType
|
|
||||||
{
|
|
||||||
return switch(token.tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Or => BinopType.LogicalOr,
|
|
||||||
TokenType.And => BinopType.LocicalAnd,
|
|
||||||
TokenType.Lt => BinopType.Lt,
|
|
||||||
TokenType.Gt => BinopType.Gt,
|
|
||||||
TokenType.LtEquals => BinopType.LtEquals,
|
|
||||||
TokenType.GtEquals => BinopType.GtEquals,
|
|
||||||
TokenType.LtLt => BinopType.Shl,
|
|
||||||
TokenType.GtGt=> BinopType.Shr,
|
|
||||||
TokenType.TildeEquals => BinopType.NotEquals,
|
|
||||||
TokenType.EqualsEquals => BinopType.Equals,
|
|
||||||
TokenType.Pipe => BinopType.BinaryOr,
|
|
||||||
TokenType.Tilde => BinopType.BinaryNot,
|
|
||||||
TokenType.Ampersand => BinopType.BinaryAnd,
|
|
||||||
TokenType.DotDot => BinopType.Concat,
|
|
||||||
TokenType.Plus => BinopType.Add,
|
|
||||||
TokenType.Minus => BinopType.Sub,
|
|
||||||
TokenType.Star => BinopType.Mul,
|
|
||||||
TokenType.Slash => BinopType.Div,
|
|
||||||
TokenType.SlashSlash => BinopType.IntDiv,
|
|
||||||
TokenType.Percent => BinopType.Mod,
|
|
||||||
TokenType.Caret => BinopType.Exp,
|
|
||||||
else => error.NoBinopTypeForOperator,
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
fn getPrecedence(token: Token) !u8
|
|
||||||
{
|
|
||||||
return switch(token.tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Or => 2,
|
|
||||||
TokenType.And => 4,
|
|
||||||
TokenType.Lt, TokenType.Gt, TokenType.LtEquals, TokenType.GtEquals, TokenType.TildeEquals, TokenType.EqualsEquals => 6,
|
|
||||||
TokenType.Pipe => 8,
|
|
||||||
TokenType.Tilde => 10,
|
|
||||||
TokenType.Ampersand => 12,
|
|
||||||
TokenType.LtLt, TokenType.GtGt => 14,
|
|
||||||
TokenType.DotDot => 16,
|
|
||||||
TokenType.Plus, TokenType.Minus => 18,
|
|
||||||
TokenType.Star, TokenType.Slash, TokenType.SlashSlash, TokenType.Percent => 20,
|
|
||||||
TokenType.Caret => 22,
|
|
||||||
else => error.NoPrecedenceForOperator,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
fn isBinop(token: Token) bool
|
|
||||||
{
|
|
||||||
return switch(token.tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Or, TokenType.And, TokenType.Lt, TokenType.Gt, TokenType.LtEquals, TokenType.GtEquals, TokenType.TildeEquals, TokenType.EqualsEquals,
|
|
||||||
TokenType.Pipe, TokenType.Tilde, TokenType.Ampersand, TokenType.LtLt, TokenType.GtGt, TokenType.DotDot, TokenType.Plus, TokenType.Minus,
|
|
||||||
TokenType.Star, TokenType.Slash, TokenType.SlashSlash, TokenType.Percent, TokenType.Caret => true,
|
|
||||||
else => false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
fn parseExplist(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !ExplistNode
|
|
||||||
{
|
|
||||||
const startRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
var ret = ExplistNode { .exps = std.ArrayList(ExpNode).init(allocator.allocator()), .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
try ret.exps.append(try parseExp(tokens, i, allocator));
|
|
||||||
while(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Comma)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
try ret.exps.append(try parseExp(tokens, i, allocator));
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseFuncname(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !FuncnameNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedFuncname;
|
|
||||||
}
|
|
||||||
const startRange = tokens[i.*].region;
|
|
||||||
var ret = FuncnameNode { .name = tokens[i.*].tokenData.string, .dottedNames = std.ArrayList([]u8).init(allocator.allocator()), .firstArg = null, .startRegion = startRange, .endRegion = startRange };
|
|
||||||
i.* += 1;
|
|
||||||
while(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Dot)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameInDottedFuncname;
|
|
||||||
}
|
|
||||||
try ret.dottedNames.append(tokens[i.*].tokenData.string);
|
|
||||||
}
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Colon)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameOfFirstArgInFuncname;
|
|
||||||
}
|
|
||||||
ret.firstArg = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseFuncbody(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !FuncbodyNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.RoundOpen)
|
|
||||||
{
|
|
||||||
return error.ExpectedRoundOpenStartingFuncbody;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInFuncbodyParlist;
|
|
||||||
}
|
|
||||||
var pars: ?ParlistNode = null;
|
|
||||||
if(tokens[i.*].tokenType == TokenType.RoundClosed)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pars = try parseParlist(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.RoundClosed)
|
|
||||||
{
|
|
||||||
return error.ExpectedRoundClosedClosingFuncbodyParlist;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
}
|
|
||||||
const ret = FuncbodyNode { .body = try parseBlock(tokens, i, allocator), .pars = pars, .startRegion = startRegion, .endRegion = tokens[i.*].region };
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.End)
|
|
||||||
{
|
|
||||||
return error.ExpectedEndClosingFuncbody;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseParlist(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !ParlistNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInParlist;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
if(tokens[i.*].tokenType == TokenType.DotDotDot)
|
|
||||||
{
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return ParlistNode { .names = std.ArrayList([]u8).init(allocator.allocator()), .hasVarargs = true, .startRegion = startRegion, .endRegion = endRegion };
|
|
||||||
}
|
|
||||||
if(tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameStartingParlist;
|
|
||||||
}
|
|
||||||
var ret = ParlistNode { .names = std.ArrayList([]u8).init(allocator.allocator()), .hasVarargs = false, .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
try ret.names.append(tokens[i.*].tokenData.string);
|
|
||||||
i.* += 1;
|
|
||||||
while(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Comma)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInParlistNameList;
|
|
||||||
}
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Name =>
|
|
||||||
{
|
|
||||||
try ret.names.append(tokens[i.*].tokenData.string);
|
|
||||||
i.* += 1;
|
|
||||||
},
|
|
||||||
TokenType.DotDotDot =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
ret.hasVarargs = true;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
else => return error.UnexpectedTokenInParlistNameList,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseAttnamelist(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !AttnamelistNode
|
|
||||||
{
|
|
||||||
// TODO: What happens if this is reaches EOF?
|
|
||||||
var ret = AttnamelistNode { .attnames = std.ArrayList(AttnameNode).init(allocator.allocator()), .startRegion = tokens[i.*].region, .endRegion = tokens[i.*].region };
|
|
||||||
try ret.attnames.append(try parseAttname(tokens, i));
|
|
||||||
while(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Comma)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
try ret.attnames.append(try parseAttname(tokens, i));
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseSuffixExp(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !SuffixexpNode
|
|
||||||
{
|
|
||||||
// primaryexp { '.' 'Name' | '[' exp']' | ':' 'Name' args | args }
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInSuffixExp;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
const firstPart = try switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Name =>
|
|
||||||
nameBlock: {
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
break :nameBlock SuffixexpFirstPart { .Name = name };
|
|
||||||
},
|
|
||||||
TokenType.RoundOpen =>
|
|
||||||
roundOpenBlock: {
|
|
||||||
i.* += 1;
|
|
||||||
const ret = SuffixexpFirstPart { .BracketedExpr = try parseExp(tokens, i, allocator) };
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.RoundClosed)
|
|
||||||
{
|
|
||||||
return error.ExpectedRoundClosedClosingBracketedPrimaryExp;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
break :roundOpenBlock ret;
|
|
||||||
},
|
|
||||||
else => error.UnexpectedTokenAsFirstPartOfSuffixExp,
|
|
||||||
};
|
|
||||||
var suffixes = std.ArrayList(SuffixexpSuffix).init(allocator.allocator());
|
|
||||||
while(i.* < tokens.len)
|
|
||||||
{
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.Dot =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameInDottedSuffixExp;
|
|
||||||
}
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
try suffixes.append(SuffixexpSuffix { .Dot = name });
|
|
||||||
},
|
|
||||||
TokenType.SquareOpen =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
try suffixes.append(SuffixexpSuffix { .Indexed = try parseExp(tokens, i, allocator) });
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.SquareClosed)
|
|
||||||
{
|
|
||||||
return error.ExpectedSquareClosedClosingIndexedSuffixExp;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
},
|
|
||||||
TokenType.Colon =>
|
|
||||||
{
|
|
||||||
const argsFirstArgStartRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedNameInArgsFirstArgSuffixExp;
|
|
||||||
}
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
const argsFirstArgEndRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
try suffixes.append(SuffixexpSuffix { .ArgsFirstArg = ArgsFirstArgNode { .name = name, .rest = try parseArgs(tokens, i, allocator), .startRegion = argsFirstArgStartRegion, .endRegion = argsFirstArgEndRegion } });
|
|
||||||
},
|
|
||||||
TokenType.RoundOpen, TokenType.CurlyOpen, TokenType.StringLiteral =>
|
|
||||||
{
|
|
||||||
try suffixes.append(SuffixexpSuffix { .Args = try parseArgs(tokens, i, allocator) });
|
|
||||||
},
|
|
||||||
else => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
const last = suffixes.getLastOrNull();
|
|
||||||
if(last != null)
|
|
||||||
{
|
|
||||||
switch(last.?)
|
|
||||||
{
|
|
||||||
SuffixexpSuffix.Args => |*args|
|
|
||||||
{
|
|
||||||
_ = suffixes.pop();
|
|
||||||
const functioncall = try allocator.allocator().create(FunctioncallNode);
|
|
||||||
functioncall.* = FunctioncallNode
|
|
||||||
{
|
|
||||||
.function = SuffixexpNode { .Normal = NormalSuffixNode { .firstPart = firstPart, .suffixes = suffixes, .startRegion = startRegion, .endRegion = endRegion } },
|
|
||||||
.args = args.*,
|
|
||||||
.objectArg = null,
|
|
||||||
.startRegion = startRegion,
|
|
||||||
.endRegion = endRegion,
|
|
||||||
};
|
|
||||||
return SuffixexpNode
|
|
||||||
{
|
|
||||||
.Functioncall = functioncall,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
SuffixexpSuffix.ArgsFirstArg => |*node|
|
|
||||||
{
|
|
||||||
_ = suffixes.pop();
|
|
||||||
const functioncall = try allocator.allocator().create(FunctioncallNode);
|
|
||||||
functioncall.* = FunctioncallNode
|
|
||||||
{
|
|
||||||
.function = SuffixexpNode { .Normal = NormalSuffixNode { .firstPart = firstPart, .suffixes = suffixes, .startRegion = startRegion, .endRegion = endRegion } },
|
|
||||||
.args = node.rest,
|
|
||||||
.objectArg = node.name,
|
|
||||||
.startRegion = startRegion,
|
|
||||||
.endRegion = endRegion,
|
|
||||||
};
|
|
||||||
return SuffixexpNode
|
|
||||||
{
|
|
||||||
.Functioncall = functioncall,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
else => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SuffixexpNode { .Normal = NormalSuffixNode { .firstPart = firstPart, .suffixes = suffixes, .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
}
|
|
||||||
fn parseVar(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !VarNode
|
|
||||||
{
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
return suffixExpToVar(try parseSuffixExp(tokens, i, allocator), startRegion, tokens[@min(i.*, tokens.len) - 1].region);
|
|
||||||
}
|
|
||||||
fn parseAttname(tokens: []Token, i: *usize) !AttnameNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectednameInAttribName;
|
|
||||||
}
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
var ret = AttnameNode { .name = name, .attribute = null, .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.Lt)
|
|
||||||
{
|
|
||||||
ret.attribute = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Name)
|
|
||||||
{
|
|
||||||
return error.ExpectedAttributeInAttrib;
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Gt)
|
|
||||||
{
|
|
||||||
return error.ExpectedGtInAttrib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseArgs(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !ArgsNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInArgs;
|
|
||||||
}
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.RoundOpen =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInBracketedArgs;
|
|
||||||
}
|
|
||||||
if(tokens[i.*].tokenType == TokenType.RoundClosed)
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
return ArgsNode { .Bracketed = null };
|
|
||||||
}
|
|
||||||
const exps = try parseExplist(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.RoundClosed)
|
|
||||||
{
|
|
||||||
return error.ExpectedRoundClosedClosingBracketedArgs;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
return ArgsNode { .Bracketed = exps };
|
|
||||||
},
|
|
||||||
TokenType.CurlyOpen => return ArgsNode { .Tableconstructor = try parseTableconstructor(tokens, i, allocator) },
|
|
||||||
TokenType.StringLiteral =>
|
|
||||||
{
|
|
||||||
const value = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 1;
|
|
||||||
return ArgsNode { .Literal = value };
|
|
||||||
},
|
|
||||||
else => return error.UnexpectedTokenInArgs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn parseTableconstructor(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !TableconstructorNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.CurlyOpen)
|
|
||||||
{
|
|
||||||
return error.ExpectedCurlyOpenOpeningTableconstructor;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* < tokens.len and tokens[i.*].tokenType == TokenType.CurlyClosed)
|
|
||||||
{
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return TableconstructorNode { .exps = null, .startRegion = startRegion, .endRegion = endRegion };
|
|
||||||
}
|
|
||||||
var ret = TableconstructorNode { .exps = try parseFieldlist(tokens, i, allocator), .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.CurlyClosed)
|
|
||||||
{
|
|
||||||
return error.ExpectedCurlyClosedClosingTableconstructor;
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn parseFieldlist(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !FieldlistNode
|
|
||||||
{
|
|
||||||
const startRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
var ret = FieldlistNode { .exps = std.ArrayList(FieldNode).init(allocator.allocator()), .startRegion = startRegion, .endRegion = startRegion };
|
|
||||||
try ret.exps.append(try parseField(tokens, i, allocator));
|
|
||||||
while(i.* < tokens.len and isFieldsep(tokens[i.*]))
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
try ret.exps.append(try parseField(tokens, i, allocator));
|
|
||||||
}
|
|
||||||
if(i.* < tokens.len and isFieldsep(tokens[i.*]))
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
}
|
|
||||||
ret.endRegion = tokens[@min(i.*, tokens.len) - 1].region;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fn isFieldsep(token: Token) bool
|
|
||||||
{
|
|
||||||
return token.tokenType == TokenType.Comma or token.tokenType == TokenType.Semicolon;
|
|
||||||
}
|
|
||||||
fn parseField(tokens: []Token, i: *usize, allocator: *std.heap.ArenaAllocator) !FieldNode
|
|
||||||
{
|
|
||||||
if(i.* >= tokens.len)
|
|
||||||
{
|
|
||||||
return error.ReachedEOFInField;
|
|
||||||
}
|
|
||||||
const startRegion = tokens[i.*].region;
|
|
||||||
switch(tokens[i.*].tokenType)
|
|
||||||
{
|
|
||||||
TokenType.SquareOpen =>
|
|
||||||
{
|
|
||||||
i.* += 1;
|
|
||||||
const index = try parseExp(tokens, i, allocator);
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.SquareClosed)
|
|
||||||
{
|
|
||||||
return error.ExpectedSquareClosedClosingIndexedField;
|
|
||||||
}
|
|
||||||
i.* += 1;
|
|
||||||
if(i.* >= tokens.len or tokens[i.*].tokenType != TokenType.Equals)
|
|
||||||
{
|
|
||||||
return error.ExpectedEqualsInIndexedFieldExpression;
|
|
||||||
}
|
|
||||||
const endRegion = tokens[i.*].region;
|
|
||||||
i.* += 1;
|
|
||||||
return FieldNode { .IndexedAssignment = IndexedAssignmentNode { .index = index, .rhs = try parseExp(tokens, i, allocator), .startRegion = startRegion, .endRegion = endRegion } };
|
|
||||||
},
|
|
||||||
TokenType.Name =>
|
|
||||||
{
|
|
||||||
if(i.* + 1 < tokens.len and tokens[i.* + 1].tokenType == TokenType.Equals)
|
|
||||||
{
|
|
||||||
const name = tokens[i.*].tokenData.string;
|
|
||||||
i.* += 2;
|
|
||||||
return FieldNode { .Assignment = FieldAssignmentNode { .lhs = name, .rhs = try parseExp(tokens, i, allocator), .startRegion = startRegion, .endRegion = tokens[i.* - 1].region } };
|
|
||||||
}
|
|
||||||
return FieldNode { .Exp = try parseExp(tokens, i, allocator) };
|
|
||||||
},
|
|
||||||
else => return FieldNode { .Exp = try parseExp(tokens, i, allocator) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn suffixExpToVar(suffixexp: SuffixexpNode, startRegion: CodeRegion, endRegion: CodeRegion) !VarNode
|
|
||||||
{
|
|
||||||
var exp = suffixexp.Normal;
|
|
||||||
if(exp.suffixes.items.len == 0)
|
|
||||||
{
|
|
||||||
return VarNode { .Name = exp.firstPart.Name };
|
|
||||||
}
|
|
||||||
const last = exp.suffixes.pop();
|
|
||||||
return switch(last)
|
|
||||||
{
|
|
||||||
SuffixexpSuffix.Dot => |*name| VarNode { .Member = MemberVarNode { .name = name.*, .value = SuffixexpNode { .Normal = exp }, .startRegion = startRegion, .endRegion = endRegion } },
|
|
||||||
SuffixexpSuffix.Indexed => |*index| VarNode { .Indexed = IndexedVarNode { .index = index.*, .value = SuffixexpNode { .Normal = exp }, .startRegion = startRegion, .endRegion = endRegion } },
|
|
||||||
else => error.ExpectedDotOrIndexedSuffixWhenConvertingSuffixExpToVar,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
-1246
@@ -1,1246 +0,0 @@
|
|||||||
const types = @import("types.zig");
|
|
||||||
const std = @import("std");
|
|
||||||
const CodeRegion = @import("types.zig").CodeRegion;
|
|
||||||
const CodeLocation = @import("types.zig").CodeLocation;
|
|
||||||
|
|
||||||
pub const TokenType = enum
|
|
||||||
{
|
|
||||||
Name,
|
|
||||||
And, Break, Do, Else, Elseif, End,
|
|
||||||
False, For, Function, Goto, If, In,
|
|
||||||
Local, Nil, Not, Or, Repeat, Return,
|
|
||||||
Then, True, Until, While,
|
|
||||||
Plus, Minus, Star, Slash, Percent, Caret, Hash,
|
|
||||||
Ampersand, Tilde, Pipe, LtLt, GtGt, SlashSlash,
|
|
||||||
EqualsEquals, TildeEquals, LtEquals, GtEquals, Lt, Gt, Equals,
|
|
||||||
RoundOpen, RoundClosed, CurlyOpen, CurlyClosed, SquareOpen, SquareClosed, ColonColon,
|
|
||||||
Semicolon, Colon, Comma, Dot, DotDot, DotDotDot,
|
|
||||||
Numeral,
|
|
||||||
StringLiteral,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const TokenData = union(enum)
|
|
||||||
{
|
|
||||||
string: []u8,
|
|
||||||
numeral: types.Numeral,
|
|
||||||
none,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Token = struct
|
|
||||||
{
|
|
||||||
tokenType: TokenType,
|
|
||||||
tokenData: TokenData,
|
|
||||||
region: CodeRegion,
|
|
||||||
};
|
|
||||||
|
|
||||||
const TokenizerState = enum
|
|
||||||
{
|
|
||||||
Start,
|
|
||||||
Quote, SingleQuote, Name, Number, Zero,
|
|
||||||
A, B, D, E, F, G, I, L, N, O, R, T, U, W,
|
|
||||||
Plus, Minus, Star, Slash, Percent, Caret, Hash,
|
|
||||||
Ampersand, Tilde, Pipe, Lt, Gt, Equals, RoundOpen, RoundClosed, CurlyOpen, CurlyClosed, SquareOpen, SquareClosed,
|
|
||||||
Colon, Semicolon, Comma, Dot,
|
|
||||||
|
|
||||||
An, Br, Do, El, En, Fa, Fo, Fu, Go, If, In, Lo, Ni, No, Or, Re, Th, Tr, Un, Wh,
|
|
||||||
LtLt, GtGt, SlashSlash, EqualsEquals, TildeEquals, LtEquals, GtEquals, ColonColon, DotDot,
|
|
||||||
SmallCommentStart, QuoteBackslash, SingleQuoteBackslash, String, HexNumberX, ExpNumber,
|
|
||||||
|
|
||||||
And, Bre, Els, End, Fal, For, Fun, Got, Loc, Nil, Not, Rep, Ret, The, Tru, Unt, Whi,
|
|
||||||
DotDotDot, HexNumber, QuoteBackslashZ, SingleQuoteBackslashZ,
|
|
||||||
BigCommentLongBracketStart, SmallComment,
|
|
||||||
|
|
||||||
Brea, Else, Fals, Func, Goto, Loca, Repe, Retu, Then, True, Unti, Whil, HexExpNumber,
|
|
||||||
BigComment, BigCommentLongBracketEnd,
|
|
||||||
|
|
||||||
Break, Elsei, False, Funct, Local, Repea, Retur, Until, While,
|
|
||||||
|
|
||||||
Elseif, Functi, Repeat, Return,
|
|
||||||
|
|
||||||
Functio,
|
|
||||||
|
|
||||||
Function,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn tokenizeUpdateIndexAndState(lastIndex: *?usize, index: ?usize, state: *TokenizerState, newState: TokenizerState, region: *CodeRegion) void
|
|
||||||
{
|
|
||||||
lastIndex.* = index;
|
|
||||||
state.* = newState;
|
|
||||||
if(index == null)
|
|
||||||
{
|
|
||||||
region.*.start = null;
|
|
||||||
region.*.length = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(region.*.start == null)
|
|
||||||
{
|
|
||||||
// TODO: There is no line/col info here and plumbing it to here would be pain.
|
|
||||||
region.*.start = CodeLocation { .col = 0, .line = 0 };
|
|
||||||
}
|
|
||||||
region.*.length += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn tokenizeTerminalBase(lastIndex: *?usize, index: ?usize, tokenType: *?TokenType, state: *TokenizerState, newTokenType: ?TokenType, newState: TokenizerState, region: *CodeRegion) void
|
|
||||||
{
|
|
||||||
tokenizeUpdateIndexAndState(lastIndex, index, state, newState, region);
|
|
||||||
tokenType.* = newTokenType;
|
|
||||||
}
|
|
||||||
fn tokenizeTerminalStr(lastIndex: *?usize, index: usize, tokenType: *?TokenType, state: *TokenizerState, newTokenType: ?TokenType, newState: TokenizerState, tokenStr: *std.ArrayList(u8), ch: u8, region: *CodeRegion) !void
|
|
||||||
{
|
|
||||||
tokenizeTerminalBase(lastIndex, index, tokenType, state, newTokenType, newState, region);
|
|
||||||
try tokenStr.append(ch);
|
|
||||||
}
|
|
||||||
fn tokenizeTerminalIntNum(lastIndex: *?usize, index: usize, tokenType: *?TokenType, state: *TokenizerState, newTokenType: TokenType, newState: TokenizerState, tokenNumeral: *?types.Numeral, ch: u8, region: *CodeRegion) !void
|
|
||||||
{
|
|
||||||
tokenizeTerminalBase(lastIndex, index, tokenType, state, newTokenType, newState, region);
|
|
||||||
if(!std.ascii.isDigit(ch))
|
|
||||||
{
|
|
||||||
return error.NoDigit;
|
|
||||||
}
|
|
||||||
const digitValue = @as(i64, ch - '0');
|
|
||||||
if(tokenNumeral.* == null)
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = digitValue };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(tokenNumeral.*.?)
|
|
||||||
{
|
|
||||||
.Integer => |*n| n.* = n.* * 10 + digitValue,
|
|
||||||
.Float => return error.ExpectedIntGotFloat
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn tokenizeTerminalNoToken(lastIndex: *?usize, index: usize, state: *TokenizerState, newState: TokenizerState, tokenStr: *std.ArrayList(u8), ch: u8, region: *CodeRegion) !void
|
|
||||||
{
|
|
||||||
tokenizeUpdateIndexAndState(lastIndex, index, state, newState, region);
|
|
||||||
try tokenStr.*.append(ch);
|
|
||||||
}
|
|
||||||
fn tokenizeBacktrack(lastIndex: *?usize, index: *usize, tokens: *std.ArrayList(Token), tokenType: *?TokenType, tokenStr: *std.ArrayList(u8), tokenNumeral: *?types.Numeral, state: *TokenizerState, allocator: std.mem.Allocator, region: *CodeRegion) !void
|
|
||||||
{
|
|
||||||
try tokenizeBacktrackCustomToken(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, tokenType.*.?, allocator, region);
|
|
||||||
}
|
|
||||||
fn tokenizeBacktrackCustomToken(lastIndex: *?usize, index: *usize, tokens: *std.ArrayList(Token), tokenType: *?TokenType, tokenStr: *std.ArrayList(u8), tokenNumeral: *?types.Numeral, state: *TokenizerState, newTokenType: TokenType, allocator: std.mem.Allocator, region: *CodeRegion) !void
|
|
||||||
{
|
|
||||||
if(lastIndex.* == null or tokenType.* == null)
|
|
||||||
{
|
|
||||||
return error.LexError;
|
|
||||||
}
|
|
||||||
if(newTokenType == TokenType.StringLiteral or newTokenType == TokenType.Name)
|
|
||||||
{
|
|
||||||
const content = try allocator.alloc(u8, tokenStr.*.items.len);
|
|
||||||
@memcpy(content, tokenStr.*.items);
|
|
||||||
try tokens.append(Token { .tokenType = newTokenType, .tokenData = TokenData { .string = content }, .region = region.* });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try tokens.append(Token { .tokenType = newTokenType, .region = region.*, .tokenData = if(tokenType.*.? == TokenType.Numeral) TokenData { .numeral = tokenNumeral.*.? }
|
|
||||||
else TokenData.none
|
|
||||||
});
|
|
||||||
}
|
|
||||||
tokenNumeral.* = null;
|
|
||||||
index.* = lastIndex.*.?;
|
|
||||||
tokenStr.*.clearAndFree();
|
|
||||||
// region is reset in tokenizeTerminalBase since null is passed as index
|
|
||||||
tokenizeTerminalBase(lastIndex, null, tokenType, state, null, TokenizerState.Start, region);
|
|
||||||
}
|
|
||||||
fn tokenizeAlphanumericNonstart(lastIndex: *?usize, index: *usize, tokens: *std.ArrayList(Token), tokenType: *?TokenType, tokenStr: *std.ArrayList(u8), tokenNumeral: *?types.Numeral, state: *TokenizerState, ch: u8, newTokenType: TokenType, allocator: std.mem.Allocator, region: *CodeRegion) !void
|
|
||||||
{
|
|
||||||
if(std.ascii.isAlphanumeric(ch) or ch == '_')
|
|
||||||
{
|
|
||||||
try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.Name, tokenStr, ch, region);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try tokenizeBacktrackCustomToken(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, newTokenType, allocator, region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn tokenizeChar(state: *TokenizerState, ch: u8, lastIndex: *?usize, index: *usize, tokenType: *?TokenType, tokenStr: *std.ArrayList(u8), tokenNumeral: *?types.Numeral, tokens: *std.ArrayList(Token), longBracketLevel: *u32, region: *CodeRegion, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
switch(state.*)
|
|
||||||
{
|
|
||||||
TokenizerState.Start =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'-' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Minus, TokenizerState.Minus, region),
|
|
||||||
',' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Comma, TokenizerState.Comma, region),
|
|
||||||
'=' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Equals, TokenizerState.Equals, region),
|
|
||||||
'(' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.RoundOpen, TokenizerState.RoundOpen, region),
|
|
||||||
')' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.RoundClosed, TokenizerState.RoundClosed, region),
|
|
||||||
'.' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Dot, TokenizerState.Dot, region),
|
|
||||||
':' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Colon, TokenizerState.Colon, region),
|
|
||||||
'{' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.CurlyOpen, TokenizerState.CurlyOpen, region),
|
|
||||||
'}' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.CurlyClosed, TokenizerState.CurlyClosed, region),
|
|
||||||
'[' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.SquareOpen, TokenizerState.SquareOpen, region),
|
|
||||||
']' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.SquareClosed, TokenizerState.SquareClosed, region),
|
|
||||||
'+' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Plus, TokenizerState.Plus, region),
|
|
||||||
'~' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Tilde, TokenizerState.Tilde, region),
|
|
||||||
'>' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Gt, TokenizerState.Gt, region),
|
|
||||||
'<' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Lt, TokenizerState.Lt, region),
|
|
||||||
'#' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Hash, TokenizerState.Hash, region),
|
|
||||||
'|' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Pipe, TokenizerState.Pipe, region),
|
|
||||||
'&' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Ampersand, TokenizerState.Ampersand, region),
|
|
||||||
'%' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Percent, TokenizerState.Percent, region),
|
|
||||||
'*' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Star, TokenizerState.Star, region),
|
|
||||||
'/' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Slash, TokenizerState.Slash, region),
|
|
||||||
';' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Semicolon, TokenizerState.Semicolon, region),
|
|
||||||
'^' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.Caret, TokenizerState.Caret, region),
|
|
||||||
'a' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.A, tokenStr, ch, region),
|
|
||||||
'b' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.B, tokenStr, ch, region),
|
|
||||||
'd' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.D, tokenStr, ch, region),
|
|
||||||
'e' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.E, tokenStr, ch, region),
|
|
||||||
'f' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.F, tokenStr, ch, region),
|
|
||||||
'i' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.I, tokenStr, ch, region),
|
|
||||||
'g' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.G, tokenStr, ch, region),
|
|
||||||
'l' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.L, tokenStr, ch, region),
|
|
||||||
'n' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.N, tokenStr, ch, region),
|
|
||||||
'o' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.O, tokenStr, ch, region),
|
|
||||||
'r' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.R, tokenStr, ch, region),
|
|
||||||
't' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.T, tokenStr, ch, region),
|
|
||||||
'u' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.U, tokenStr, ch, region),
|
|
||||||
'w' => try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.W, tokenStr, ch, region),
|
|
||||||
'0' => try tokenizeTerminalIntNum(lastIndex, index.*, tokenType, state, TokenType.Numeral, TokenizerState.Zero, tokenNumeral, ch, region),
|
|
||||||
'"' =>
|
|
||||||
{
|
|
||||||
tokenType.* = null;
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'\'' =>
|
|
||||||
{
|
|
||||||
tokenType.* = null;
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
if(std.ascii.isWhitespace(ch))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else if(std.ascii.isAlphabetic(ch) or ch == '_')
|
|
||||||
{
|
|
||||||
try tokenizeTerminalStr(lastIndex, index.*, tokenType, state, TokenType.Name, TokenizerState.Name, tokenStr, ch, region);
|
|
||||||
}
|
|
||||||
else if(std.ascii.isDigit(ch))
|
|
||||||
{
|
|
||||||
try tokenizeTerminalIntNum(lastIndex, index.*, tokenType, state, TokenType.Numeral, TokenizerState.Number, tokenNumeral, ch, region);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std.debug.print("{}: {c}\n", .{state.*, ch});
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Quote =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'\\' => state.* = TokenizerState.QuoteBackslash,
|
|
||||||
'"' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.StringLiteral, TokenizerState.String, region),
|
|
||||||
else => try tokenStr.*.append(ch),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.QuoteBackslash =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'a' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{0007}');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'b' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{0008}');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
't' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\t');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'n' | '\n' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\n');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'v' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{000b}');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'f' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{000c}');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'r' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\r');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'\\' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\\');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'"' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\"');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'\'' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\'');
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
},
|
|
||||||
'z' =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.QuoteBackslashZ;
|
|
||||||
},
|
|
||||||
else => return error.UnknownEscapeSequence,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.QuoteBackslashZ =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'\\' => state.* = TokenizerState.QuoteBackslash,
|
|
||||||
'"' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.StringLiteral, TokenizerState.String, region),
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
if(!std.ascii.isWhitespace(ch))
|
|
||||||
{
|
|
||||||
try tokenStr.append(ch);
|
|
||||||
state.* = TokenizerState.Quote;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Noop, https://www.lua.org/manual/5.4/manual.html#3.1:
|
|
||||||
// "The escape sequence '\z' skips the following span of whitespace characters, including line breaks;"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.SingleQuote =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'\\' => state.* = TokenizerState.SingleQuoteBackslash,
|
|
||||||
'\'' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.StringLiteral, TokenizerState.String, region),
|
|
||||||
else => try tokenStr.append(ch),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.SingleQuoteBackslash =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'a' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{0007}');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'b' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{0008}');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
't' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\t');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'n' | '\n' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\n');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'v' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{000b}');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'f' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\u{000c}');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'r' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\r');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'\\' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\\');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'"' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\"');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'\'' =>
|
|
||||||
{
|
|
||||||
try tokenStr.append('\'');
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
},
|
|
||||||
'z' =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.SingleQuoteBackslashZ;
|
|
||||||
},
|
|
||||||
else => return error.UnknownEscapeSequence,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.SingleQuoteBackslashZ =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'\\' => state.* = TokenizerState.SingleQuoteBackslash,
|
|
||||||
'\'' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.StringLiteral, TokenizerState.String, region),
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
if(!std.ascii.isWhitespace(ch))
|
|
||||||
{
|
|
||||||
try tokenStr.append(ch);
|
|
||||||
state.* = TokenizerState.SingleQuote;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Noop, https://www.lua.org/manual/5.4/manual.html#3.1:
|
|
||||||
// "The escape sequence '\z' skips the following span of whitespace characters, including line breaks;"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.String => try tokenizeBacktrackCustomToken(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, TokenType.StringLiteral, allocator, region),
|
|
||||||
TokenizerState.Name => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
TokenizerState.Zero =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'x' =>
|
|
||||||
{
|
|
||||||
try tokenStr.*.append(ch);
|
|
||||||
tokenType.* = null;
|
|
||||||
state.* = TokenizerState.HexNumberX;
|
|
||||||
},
|
|
||||||
'.' => return error.NotImplemented,
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
if(std.ascii.isDigit(ch))
|
|
||||||
{
|
|
||||||
const digitValue = @as(i64, ch - '0');
|
|
||||||
lastIndex.* = index.*;
|
|
||||||
if(tokenNumeral.* == null)
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = digitValue };
|
|
||||||
tokenType.* = TokenType.Numeral;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tokenNumeral.*.?.Integer = tokenNumeral.*.?.Integer * 10 + digitValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.HexNumberX =>
|
|
||||||
{
|
|
||||||
if(std.ascii.isHex(ch))
|
|
||||||
{
|
|
||||||
lastIndex.* = index.*;
|
|
||||||
tokenType.* = TokenType.Numeral;
|
|
||||||
if(std.ascii.isDigit(ch))
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = @as(i64, ch - '0') };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = @as(i64, std.ascii.toLower(ch) - 'a') };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.HexNumber =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'p' =>
|
|
||||||
{
|
|
||||||
try tokenStr.*.append(ch);
|
|
||||||
tokenType.* = null;
|
|
||||||
state.* = TokenizerState.HexExpNumber;
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
if(std.ascii.isHex(ch))
|
|
||||||
{
|
|
||||||
lastIndex.* = index.*;
|
|
||||||
tokenType.* = TokenType.Numeral;
|
|
||||||
if(std.ascii.isDigit(ch))
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = @as(i64, ch - '0') };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = @as(i64, std.ascii.toLower(ch) - 'a') };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Number =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' =>
|
|
||||||
{
|
|
||||||
try tokenStr.*.append(ch);
|
|
||||||
tokenType.* = null;
|
|
||||||
state.* = TokenizerState.ExpNumber;
|
|
||||||
},
|
|
||||||
'.' => return error.NotImplemented,
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
if(std.ascii.isDigit(ch))
|
|
||||||
{
|
|
||||||
const digitValue = @as(i64, ch - '0');
|
|
||||||
lastIndex.* = index.*;
|
|
||||||
if(tokenNumeral.* == null)
|
|
||||||
{
|
|
||||||
tokenNumeral.* = types.Numeral { .Integer = digitValue };
|
|
||||||
tokenType.* = TokenType.Numeral;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tokenNumeral.*.?.Integer = tokenNumeral.*.?.Integer * 10 + digitValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Comma, TokenizerState.RoundOpen, TokenizerState.RoundClosed,
|
|
||||||
TokenizerState.CurlyOpen, TokenizerState.CurlyClosed, TokenizerState.Plus,
|
|
||||||
TokenizerState.TildeEquals, TokenizerState.EqualsEquals, TokenizerState.Hash,
|
|
||||||
TokenizerState.GtEquals, TokenizerState.LtEquals, TokenizerState.SquareOpen,
|
|
||||||
TokenizerState.SquareClosed, TokenizerState.Pipe, TokenizerState.Ampersand,
|
|
||||||
TokenizerState.Percent, TokenizerState.Star, TokenizerState.Semicolon,
|
|
||||||
TokenizerState.Caret, TokenizerState.DotDotDot, TokenizerState.GtGt,
|
|
||||||
TokenizerState.LtLt, TokenizerState.SlashSlash => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
TokenizerState.Tilde =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'=' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.TildeEquals, TokenizerState.TildeEquals, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Gt =>
|
|
||||||
{
|
|
||||||
switch (ch)
|
|
||||||
{
|
|
||||||
'>' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.GtGt, TokenizerState.GtGt, region),
|
|
||||||
'=' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.GtEquals, TokenizerState.GtEquals, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Lt =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'<' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.LtLt, TokenizerState.LtLt, region),
|
|
||||||
'=' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.LtEquals, TokenizerState.LtEquals, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Slash =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'/' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.SlashSlash, TokenizerState.SlashSlash, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Dot =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'.' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.DotDot, TokenizerState.DotDot, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.DotDot =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'.' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.DotDotDot, TokenizerState.DotDotDot, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Colon =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
':' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.ColonColon, TokenizerState.ColonColon, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Equals =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'=' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, TokenType.EqualsEquals, TokenizerState.EqualsEquals, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Minus =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'-' => tokenizeTerminalBase(lastIndex, index.*, tokenType, state, null, TokenizerState.SmallCommentStart, region),
|
|
||||||
else => try tokenizeBacktrack(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.SmallCommentStart =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'[' =>
|
|
||||||
{
|
|
||||||
tokenType.* = null;
|
|
||||||
state.* = TokenizerState.BigCommentLongBracketStart;
|
|
||||||
},
|
|
||||||
'\n' =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.Start;
|
|
||||||
lastIndex.* = null;
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.SmallComment;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.SmallComment =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'\n' =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.Start;
|
|
||||||
lastIndex.* = null;
|
|
||||||
},
|
|
||||||
else => { }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.BigCommentLongBracketStart =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'=' =>
|
|
||||||
{
|
|
||||||
longBracketLevel.* += 1;
|
|
||||||
},
|
|
||||||
'[' =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.BigComment;
|
|
||||||
},
|
|
||||||
else => return error.LongBracketMalformedStartBigComment,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.BigComment =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
']' =>
|
|
||||||
{
|
|
||||||
state.* = TokenizerState.BigCommentLongBracketEnd;
|
|
||||||
},
|
|
||||||
else => { },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.BigCommentLongBracketEnd =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'=' =>
|
|
||||||
{
|
|
||||||
if(longBracketLevel.* == 0)
|
|
||||||
{
|
|
||||||
return error.LongBracketLevelTooBigEndBigComment;
|
|
||||||
}
|
|
||||||
longBracketLevel.* -= 1;
|
|
||||||
},
|
|
||||||
']' =>
|
|
||||||
{
|
|
||||||
if(longBracketLevel.* != 0)
|
|
||||||
{
|
|
||||||
return error.LongBracketLevelTooSmallEndBigComment;
|
|
||||||
}
|
|
||||||
state.* = TokenizerState.Start;
|
|
||||||
},
|
|
||||||
else => return error.LongBracketMalformedSmallEndBigComment,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.A =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.An, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.An =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'd' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.And, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.And => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.And, allocator, region),
|
|
||||||
TokenizerState.W =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'h' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Wh, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Wh =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'i' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Whi, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Whi =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'l' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Whil, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Whil =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.While, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.While => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.While, allocator, region),
|
|
||||||
TokenizerState.B =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'r' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Br, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Br =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Bre, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Bre =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'a' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Brea, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Brea =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'k' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Break, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Break => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Break, allocator, region),
|
|
||||||
TokenizerState.G =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Go, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Go =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
't' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Got, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Got =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Goto, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Goto => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Goto, allocator, region),
|
|
||||||
TokenizerState.R =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Re, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Re =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
't' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Ret, tokenStr, ch, region),
|
|
||||||
'p' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Rep, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Ret =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'u' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Retu, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Retu =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'r' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Retur, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Retur =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Return, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Return => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Return, allocator, region),
|
|
||||||
TokenizerState.Rep =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Repe, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Repe =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'a' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Repea, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Repea =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
't' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Repeat, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Repeat => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Repeat, allocator, region),
|
|
||||||
TokenizerState.N =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'i' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Ni, tokenStr, ch, region),
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.No, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.No =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
't' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Not, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Not => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Not, allocator, region),
|
|
||||||
TokenizerState.Ni =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'l' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Nil, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Nil => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Nil, allocator, region),
|
|
||||||
TokenizerState.T =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'h' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Th, tokenStr, ch, region),
|
|
||||||
'r' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Tr, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Th =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.The, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.The =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Then, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Then => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Then, allocator, region),
|
|
||||||
TokenizerState.Tr =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'u' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Tru, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Tru =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.True, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.True => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.True, allocator, region),
|
|
||||||
TokenizerState.E =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'l' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.El, tokenStr, ch, region),
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.En, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.En =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'd' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.End, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.End => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.End, allocator, region),
|
|
||||||
TokenizerState.El =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
's' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Els, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Els =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Else, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Else =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'i' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Elsei, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Else, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Elsei =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'f' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Elseif, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Elseif => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Elseif, allocator, region),
|
|
||||||
TokenizerState.O =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'r' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Or, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Or => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Or, allocator, region),
|
|
||||||
TokenizerState.D =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Do, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Do => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Do, allocator, region),
|
|
||||||
TokenizerState.I =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'f' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.If, tokenStr, ch, region),
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.In, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.In => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.In, allocator, region),
|
|
||||||
TokenizerState.If => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.If, allocator, region),
|
|
||||||
TokenizerState.F =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'a' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Fa, tokenStr, ch, region),
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Fo, tokenStr, ch, region),
|
|
||||||
'u' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Fu, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Fu =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Fun, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Fun =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'c' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Func, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Func =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
't' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Funct, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Funct =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'i' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Functi, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Functi =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Functio, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Functio =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Function, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Function => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Function, allocator, region),
|
|
||||||
TokenizerState.Fa =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'l' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Fal, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Fal =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
's' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Fals, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Fals =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'e' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.False, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.False => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.False, allocator, region),
|
|
||||||
TokenizerState.Fo =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'r' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.For, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.For => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.For, allocator, region),
|
|
||||||
TokenizerState.L =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'o' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Lo, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Lo =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'c' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Loc, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Loc =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'a' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Loca, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Loca =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'l' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Local, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Local => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Local, allocator, region),
|
|
||||||
TokenizerState.U =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'n' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Un, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Un =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
't' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Unt, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Unt =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'i' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Unti, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Unti =>
|
|
||||||
{
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
'l' => try tokenizeTerminalNoToken(lastIndex, index.*, state, TokenizerState.Until, tokenStr, ch, region),
|
|
||||||
else => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Name, allocator, region),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TokenizerState.Until => try tokenizeAlphanumericNonstart(lastIndex, index, tokens, tokenType, tokenStr, tokenNumeral, state, ch, TokenType.Until, allocator, region),
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
std.debug.print("{}\n", . {state.*});
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tokenize(fileContent: []u8, allocator: std.mem.Allocator) ![]Token
|
|
||||||
{
|
|
||||||
var tokens = std.ArrayList(Token).init(allocator);
|
|
||||||
var state: TokenizerState = TokenizerState.Start;
|
|
||||||
var lastIndex: ?usize = null;
|
|
||||||
var index: usize = 0;
|
|
||||||
var tokenType: ?TokenType = null;
|
|
||||||
var tokenStr = std.ArrayList(u8).init(allocator);
|
|
||||||
defer tokenStr.deinit();
|
|
||||||
var tokenNumeral: ?types.Numeral = null;
|
|
||||||
var longBracketLevel: u32 = 0;
|
|
||||||
var region = CodeRegion { .start = null, .length = 0 };
|
|
||||||
|
|
||||||
while(index < fileContent.len)
|
|
||||||
{
|
|
||||||
const ch = fileContent[index];
|
|
||||||
try tokenizeChar(&state, ch, &lastIndex, &index, &tokenType, &tokenStr, &tokenNumeral, &tokens, &longBracketLevel, ®ion, allocator);
|
|
||||||
if(region.start != null and region.start.?.col == 0 and region.start.?.line == 0)
|
|
||||||
{
|
|
||||||
region.start = calculatePoint(fileContent, index);
|
|
||||||
}
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
if(longBracketLevel != 0)
|
|
||||||
{
|
|
||||||
return error.UnbalancedLongBracketLevel;
|
|
||||||
}
|
|
||||||
try tokenizeChar(&state, '\n', &lastIndex, &index, &tokenType, &tokenStr, &tokenNumeral, &tokens, &longBracketLevel, ®ion, allocator);
|
|
||||||
if(region.start != null and region.start.?.col == 0 and region.start.?.line == 0)
|
|
||||||
{
|
|
||||||
region.start = calculatePoint(fileContent, index);
|
|
||||||
}
|
|
||||||
return tokens.toOwnedSlice();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculatePoint(fileContent: []u8, index: usize) CodeLocation
|
|
||||||
{
|
|
||||||
var ret = CodeLocation { .col = 1, .line = 1 };
|
|
||||||
for(0..index) |i|
|
|
||||||
{
|
|
||||||
ret.col += 1;
|
|
||||||
if(fileContent[i] == '\n')
|
|
||||||
{
|
|
||||||
ret.line += 1;
|
|
||||||
ret.col = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const parser = @import("parser.zig");
|
|
||||||
const types = @import("types.zig");
|
|
||||||
|
|
||||||
pub fn interpret(root: parser.ChunkNode, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
var _ENV = types.Table { .entries= std.ArrayList(types.TableEntry).init(allocator) };
|
|
||||||
try walkChunk(root, &_ENV, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkChunk(node: parser.ChunkNode, environment: *types.Table, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
try walkBlock(node.block, environment, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkBlock(node: parser.BlockNode, environment: *types.Table, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
for(node.stats.items) |stat|
|
|
||||||
{
|
|
||||||
try walkStat(stat, environment, allocator);
|
|
||||||
}
|
|
||||||
if(node.retstat != null)
|
|
||||||
{
|
|
||||||
try walkRetstat(node.retstat.?, environment, allocator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkStat(node: parser.StatNode, environment: *types.Table, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
switch(node)
|
|
||||||
{
|
|
||||||
.Assignment => |assignmentNode|
|
|
||||||
{
|
|
||||||
return try walkAssignmentNode(assignmentNode, environment, allocator);
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
std.debug.print("{any}\n", .{node});
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkRetstat(node: parser.RetstatNode, environment: *types.Table, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
_ = node;
|
|
||||||
_ = environment;
|
|
||||||
_ = allocator;
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkAssignmentNode(node: parser.AssignmentNode, environment: *types.Table, allocator: std.mem.Allocator) !void
|
|
||||||
{
|
|
||||||
const results = try walkExplist(node.rhs, environment, allocator);
|
|
||||||
var i: usize = 0;
|
|
||||||
_ = results;
|
|
||||||
_ = i;
|
|
||||||
for(node.lhs.vars.items) |variable|
|
|
||||||
{
|
|
||||||
switch(variable)
|
|
||||||
{
|
|
||||||
.Indexed => |indexedNode|
|
|
||||||
{
|
|
||||||
_ = indexedNode;
|
|
||||||
return error.NotImplemented;
|
|
||||||
},
|
|
||||||
else => return error.NotImplemented,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkExplist(node: parser.ExplistNode, environment: *types.Table, allocator: std.mem.Allocator) ![]types.Value
|
|
||||||
{
|
|
||||||
var results = std.ArrayList(types.Value).init(allocator);
|
|
||||||
for(node.exps.items) |exp|
|
|
||||||
{
|
|
||||||
try results.append(try walkExp(exp, environment, allocator, false));
|
|
||||||
}
|
|
||||||
return results.toOwnedSlice();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkExp(node: parser.ExpNode, environment: *types.Table, allocator: std.mem.Allocator, isVariadicFunction: bool) !types.Value
|
|
||||||
{
|
|
||||||
switch(node)
|
|
||||||
{
|
|
||||||
.Nil => return types.Value.Nil,
|
|
||||||
.False => return types.Value { .Bool = false },
|
|
||||||
.True => return types.Value { .Bool = true },
|
|
||||||
.Numeral => |numeral| return types.Value { .Numeral = numeral },
|
|
||||||
.LiteralString => |string| return types.Value { .String = string },
|
|
||||||
.Varargs =>
|
|
||||||
{
|
|
||||||
if(isVariadicFunction)
|
|
||||||
{
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return error.UseVarargsOutsideVariadicFunction;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Suffixexp => |suffixExp|
|
|
||||||
{
|
|
||||||
return walkSuffixexp(suffixExp.*, environment, allocator);
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
std.debug.print("{}\n", .{node});
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walkSuffixexp(node: parser.SuffixexpNode, environment: *types.Table, allocator: std.mem.Allocator) !types.Value
|
|
||||||
{
|
|
||||||
_ = allocator;
|
|
||||||
switch(node)
|
|
||||||
{
|
|
||||||
.Normal => |normal|
|
|
||||||
{
|
|
||||||
switch(normal.firstPart)
|
|
||||||
{
|
|
||||||
.Name => |name|
|
|
||||||
{
|
|
||||||
std.debug.print("name: {s}\n", .{name});
|
|
||||||
std.debug.print("val: {!}\n", .{environment.get(types.Value { .String = name })});
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
std.debug.print("{}\n", .{normal.firstPart});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return error.NotImplemented;
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
std.debug.print("{}\n", .{node});
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-194
@@ -1,194 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub const NumeralTag = enum
|
|
||||||
{
|
|
||||||
Integer,
|
|
||||||
Float,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn isFloatExactInt(value: f64) bool
|
|
||||||
{
|
|
||||||
return value == 0 or (std.math.isNormal(value) and @floor(value) == value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Numeral = union(NumeralTag)
|
|
||||||
{
|
|
||||||
Integer: i64,
|
|
||||||
Float: f64,
|
|
||||||
|
|
||||||
pub fn rawEqual(self: Numeral, other: Numeral) bool
|
|
||||||
{
|
|
||||||
if(@as(NumeralTag, self) == @as(NumeralTag, other))
|
|
||||||
{
|
|
||||||
switch(self)
|
|
||||||
{
|
|
||||||
.Float => |value| return value == other.Float,
|
|
||||||
.Integer => |value| return value == other.Integer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Other is the respective other type
|
|
||||||
switch(self)
|
|
||||||
{
|
|
||||||
.Float => |value|
|
|
||||||
{
|
|
||||||
return isFloatExactInt(value) and @as(u64, @intFromFloat(value)) == other.Integer;
|
|
||||||
},
|
|
||||||
.Integer => |value|
|
|
||||||
{
|
|
||||||
return isFloatExactInt(other.Float) and @as(u64, @intFromFloat(other.Float)) == value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test "float int equality"
|
|
||||||
{
|
|
||||||
const a = Numeral { .Float = 12.0 };
|
|
||||||
const b = Numeral { .Integer = 12 };
|
|
||||||
try std.testing.expect(a.rawEqual(b));
|
|
||||||
try std.testing.expect(b.rawEqual(a));
|
|
||||||
try std.testing.expect(a.rawEqual(a));
|
|
||||||
try std.testing.expect(b.rawEqual(b));
|
|
||||||
const c = Numeral { .Float = (0.2 + 0.1) * 10.0 };
|
|
||||||
const d = Numeral { .Integer = 3 };
|
|
||||||
try std.testing.expect(c.rawEqual(d));
|
|
||||||
try std.testing.expect(d.rawEqual(c));
|
|
||||||
try std.testing.expect(c.rawEqual(c));
|
|
||||||
try std.testing.expect(d.rawEqual(d));
|
|
||||||
const e = Numeral { .Float = 3.2 };
|
|
||||||
try std.testing.expect(!a.rawEqual(e));
|
|
||||||
try std.testing.expect(!b.rawEqual(e));
|
|
||||||
try std.testing.expect(!c.rawEqual(e));
|
|
||||||
try std.testing.expect(!d.rawEqual(e));
|
|
||||||
try std.testing.expect(!e.rawEqual(a));
|
|
||||||
try std.testing.expect(!e.rawEqual(b));
|
|
||||||
try std.testing.expect(!e.rawEqual(c));
|
|
||||||
try std.testing.expect(!e.rawEqual(d));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const TableEntry = struct
|
|
||||||
{
|
|
||||||
key: Value,
|
|
||||||
value: Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Table = struct
|
|
||||||
{
|
|
||||||
entries: std.ArrayList(TableEntry),
|
|
||||||
|
|
||||||
pub fn get(self: Table, key: Value) Value
|
|
||||||
{
|
|
||||||
if(@as(ValueTag, key) == ValueTag.Nil)
|
|
||||||
{
|
|
||||||
return Value.Nil;
|
|
||||||
}
|
|
||||||
for (self.entries.items) |entry|
|
|
||||||
{
|
|
||||||
if(entry.key.rawEqual(key))
|
|
||||||
{
|
|
||||||
return entry.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Value.Nil;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ValueTag = enum
|
|
||||||
{
|
|
||||||
Nil,
|
|
||||||
Bool,
|
|
||||||
Numeral,
|
|
||||||
String,
|
|
||||||
Table,
|
|
||||||
};
|
|
||||||
pub const Value = union(ValueTag)
|
|
||||||
{
|
|
||||||
Nil,
|
|
||||||
Bool: bool,
|
|
||||||
Numeral: Numeral,
|
|
||||||
String: []const u8,
|
|
||||||
Table: *Table,
|
|
||||||
|
|
||||||
pub fn rawEqual(self: Value, other: Value) bool
|
|
||||||
{
|
|
||||||
if(@as(ValueTag, self) != @as(ValueTag, other))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch(self)
|
|
||||||
{
|
|
||||||
.Nil => return true,
|
|
||||||
.Bool => |value| return value == other.Bool,
|
|
||||||
.Numeral => |value| return value.rawEqual(other.Numeral),
|
|
||||||
.String => |value| return std.mem.eql(u8, value, other.String),
|
|
||||||
.Table => |value| return value == other.Table,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test "Value equalities"
|
|
||||||
{
|
|
||||||
const a = Value { .Bool = true };
|
|
||||||
const b = Value { .Numeral = Numeral { .Integer = 1 } };
|
|
||||||
// true != 1
|
|
||||||
try std.testing.expect(!a.rawEqual(b));
|
|
||||||
// 1 != true
|
|
||||||
try std.testing.expect(!b.rawEqual(a));
|
|
||||||
const c = Value { .Bool = false };
|
|
||||||
// true != false
|
|
||||||
try std.testing.expect(!a.rawEqual(c));
|
|
||||||
// false!= true
|
|
||||||
try std.testing.expect(!c.rawEqual(a));
|
|
||||||
const d = Value { .Bool = true };
|
|
||||||
// true == true
|
|
||||||
try std.testing.expect(a.rawEqual(d));
|
|
||||||
// true == true
|
|
||||||
try std.testing.expect(d.rawEqual(a));
|
|
||||||
const e = Value { .String = "foo" };
|
|
||||||
const f = Value { .String = "bar" };
|
|
||||||
// foo != bar
|
|
||||||
try std.testing.expect(!e.rawEqual(f));
|
|
||||||
// bar != foo
|
|
||||||
try std.testing.expect(!f.rawEqual(e));
|
|
||||||
const g = Value { .String = "foo" };
|
|
||||||
// foo != foo
|
|
||||||
try std.testing.expect(e.rawEqual(g));
|
|
||||||
// foo != foo
|
|
||||||
try std.testing.expect(g.rawEqual(e));
|
|
||||||
var table = Table { .entries = std.ArrayList(TableEntry).init(std.testing.allocator) };
|
|
||||||
const h = Value { .Table = &table };
|
|
||||||
var table2 = Table { .entries = std.ArrayList(TableEntry).init(std.testing.allocator) };
|
|
||||||
const i = Value { .Table = &table2 };
|
|
||||||
const j = Value { .Table = &table2 };
|
|
||||||
|
|
||||||
try std.testing.expect(h.rawEqual(h));
|
|
||||||
try std.testing.expect(i.rawEqual(i));
|
|
||||||
try std.testing.expect(!h.rawEqual(i));
|
|
||||||
try std.testing.expect(!i.rawEqual(h));
|
|
||||||
try std.testing.expect(i.rawEqual(j));
|
|
||||||
try std.testing.expect(!h.rawEqual(j));
|
|
||||||
}
|
|
||||||
|
|
||||||
test "Table get"
|
|
||||||
{
|
|
||||||
var a = Table { .entries = std.ArrayList(TableEntry).init(std.testing.allocator) };
|
|
||||||
defer a.entries.deinit();
|
|
||||||
try a.entries.append(TableEntry { .key = Value { .Bool = true }, .value = Value { .String = "foo" } });
|
|
||||||
try std.testing.expectEqualStrings(a.get(Value { .Bool = true }).String, "foo");
|
|
||||||
try std.testing.expectEqual(a.get(Value.Nil), Value.Nil);
|
|
||||||
try std.testing.expectEqual(a.get(Value { .Numeral = Numeral { .Integer = 12 } }), Value.Nil);
|
|
||||||
var c = a.get(Value { .Bool = true });
|
|
||||||
c.String = "bar";
|
|
||||||
try std.testing.expectEqual(a.get(Value { .Bool = true }).String, "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CodeRegion = struct
|
|
||||||
{
|
|
||||||
start: ?CodeLocation,
|
|
||||||
length: usize,
|
|
||||||
};
|
|
||||||
pub const CodeLocation = struct
|
|
||||||
{
|
|
||||||
line: usize,
|
|
||||||
col: usize,
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
a, b = 12, test(32, 4)
|
|
||||||
local t=(string.find(originalField.af,'m') and originalField.tableAction) or c.tableAction or originalField.tableAction or tableActionGeneric
|
|
||||||
b = {["a"] = 23}
|
|
||||||
for i=0, 10 do b[i] = 2^23 end
|
|
||||||
print("asdf")
|
|
||||||
function test(a, b)
|
|
||||||
return 42 + a / b
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user