feat: improved parsing and regression test suite
This commit is contained in:
parent
4ebdd3c66e
commit
619eb3b338
39 changed files with 1116 additions and 339 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
# Directories
|
||||
.cache/
|
||||
.zig-cache
|
||||
zig-out
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
build/
|
||||
build-*
|
||||
|
||||
# Temporary Files / Logs
|
||||
*.log
|
||||
|
|
|
|||
5
CMakeLists.txt
Normal file
5
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(InkCompiler LANGUAGES NONE)
|
||||
|
||||
add_subdirectory(testing/regression)
|
||||
|
|
@ -7,7 +7,6 @@ pub fn build(b: *std.Build) void {
|
|||
.root_source_file = b.path("src/root.zig"),
|
||||
.target = target,
|
||||
});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "inkc",
|
||||
.root_module = b.createModule(.{
|
||||
|
|
|
|||
215
src/Ast.zig
215
src/Ast.zig
|
|
@ -12,10 +12,14 @@ errors: []Error,
|
|||
|
||||
pub const Node = struct {
|
||||
tag: Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
loc: Span,
|
||||
data: Data,
|
||||
|
||||
pub const Span = struct {
|
||||
start: usize,
|
||||
end: usize,
|
||||
};
|
||||
|
||||
pub const Tag = enum {
|
||||
file,
|
||||
false_literal,
|
||||
|
|
@ -107,6 +111,98 @@ pub const Node = struct {
|
|||
children: ?[]*Node,
|
||||
},
|
||||
};
|
||||
|
||||
fn create(gpa: std.mem.Allocator, tag: Tag, loc: Span) !*Node {
|
||||
const node = try gpa.create(Node);
|
||||
node.* = .{ .tag = tag, .loc = loc, .data = undefined };
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createLeaf(gpa: std.mem.Allocator, tag: Tag, loc: Span) !*Node {
|
||||
const node = try Node.create(gpa, tag, loc);
|
||||
node.data = .{ .leaf = undefined };
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createBinary(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Tag,
|
||||
span: Span,
|
||||
lhs: ?*Node,
|
||||
rhs: ?*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, span);
|
||||
node.data = .{
|
||||
.bin = .{ .lhs = lhs, .rhs = rhs },
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createList(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Tag,
|
||||
span: Span,
|
||||
items: ?[]*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, span);
|
||||
node.data = .{
|
||||
.list = .{ .items = items },
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createChoice(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Tag,
|
||||
span: Span,
|
||||
start_expr: ?*Node,
|
||||
option_expr: ?*Node,
|
||||
inner_expr: ?*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, span);
|
||||
node.data = .{
|
||||
.choice_expr = .{
|
||||
.start_expr = start_expr,
|
||||
.option_expr = option_expr,
|
||||
.inner_expr = inner_expr,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createSwitch(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Tag,
|
||||
loc: Span,
|
||||
condition_expr: ?*Node,
|
||||
cases_list: ?[]*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, loc);
|
||||
node.data = .{
|
||||
.switch_stmt = .{
|
||||
.condition_expr = condition_expr,
|
||||
.cases = cases_list,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createKnot(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Tag,
|
||||
loc: Span,
|
||||
prototype: *Node,
|
||||
children: ?[]*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, loc);
|
||||
node.data = .{
|
||||
.knot_decl = .{
|
||||
.prototype = prototype,
|
||||
.children = children,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Error = struct {
|
||||
|
|
@ -134,121 +230,6 @@ pub const Error = struct {
|
|||
};
|
||||
};
|
||||
|
||||
fn create(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
) !*Node {
|
||||
const node = try gpa.create(Node);
|
||||
node.* = .{
|
||||
.tag = tag,
|
||||
.source_start = source_start,
|
||||
.source_end = source_end,
|
||||
.data = undefined,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createLeafNode(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
) !*Node {
|
||||
const node = try Ast.create(gpa, tag, source_start, source_end);
|
||||
node.*.data = .{ .leaf = undefined };
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createBinaryNode(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
lhs: ?*Node,
|
||||
rhs: ?*Node,
|
||||
) !*Node {
|
||||
const node = try Ast.create(gpa, tag, source_start, source_end);
|
||||
node.*.data = .{
|
||||
.bin = .{
|
||||
.lhs = lhs,
|
||||
.rhs = rhs,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createListNode(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
items: ?[]*Node,
|
||||
) !*Node {
|
||||
const node = try Ast.create(gpa, tag, source_start, source_end);
|
||||
node.*.data = .{
|
||||
.list = .{ .items = items },
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createChoiceExprNode(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
start_expr: ?*Node,
|
||||
option_expr: ?*Node,
|
||||
inner_expr: ?*Node,
|
||||
) !*Node {
|
||||
const node = try Ast.create(gpa, tag, source_start, source_end);
|
||||
node.*.data = .{
|
||||
.choice_expr = .{
|
||||
.start_expr = start_expr,
|
||||
.option_expr = option_expr,
|
||||
.inner_expr = inner_expr,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createSwitchNode(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
condition_expr: ?*Node,
|
||||
cases_list: ?[]*Node,
|
||||
) !*Node {
|
||||
const node = try Ast.create(gpa, tag, source_start, source_end);
|
||||
node.*.data = .{
|
||||
.switch_stmt = .{
|
||||
.condition_expr = condition_expr,
|
||||
.cases = cases_list,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn createKnotDeclNode(
|
||||
gpa: std.mem.Allocator,
|
||||
tag: Node.Tag,
|
||||
source_start: usize,
|
||||
source_end: usize,
|
||||
prototype: *Node,
|
||||
children: ?[]*Node,
|
||||
) !*Node {
|
||||
const node = try Ast.create(gpa, tag, source_start, source_end);
|
||||
node.*.data = .{
|
||||
.knot_decl = .{
|
||||
.prototype = prototype,
|
||||
.children = children,
|
||||
},
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
pub fn parse(
|
||||
gpa: std.mem.Allocator,
|
||||
arena: std.mem.Allocator,
|
||||
|
|
|
|||
|
|
@ -208,15 +208,15 @@ fn writeType(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
|
|||
|
||||
fn writeLexeme(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
|
||||
const bytes = r.tree.source;
|
||||
const lexeme = bytes[node.source_start..node.source_end];
|
||||
const lexeme = bytes[node.loc.start..node.loc.end];
|
||||
try r.tty_config.setColor(writer, .yellow);
|
||||
try writer.print("`{s}`", .{lexeme});
|
||||
try r.tty_config.setColor(writer, .reset);
|
||||
}
|
||||
|
||||
fn writeLineSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
|
||||
const line_start = r.lines.calculateLine(node.source_start);
|
||||
const line_end = r.lines.calculateLine(node.source_end);
|
||||
const line_start = r.lines.calculateLine(node.loc.start);
|
||||
const line_end = r.lines.calculateLine(node.loc.end);
|
||||
|
||||
try r.tty_config.setColor(writer, .white);
|
||||
try writer.writeByte('<');
|
||||
|
|
@ -242,10 +242,10 @@ fn writeLineSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !voi
|
|||
}
|
||||
|
||||
fn writeColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
|
||||
const line_start = r.lines.calculateLine(node.source_start);
|
||||
const line_start = r.lines.calculateLine(node.loc.start);
|
||||
const line_range = r.lines.ranges.items[line_start];
|
||||
const column_start = (node.source_start - line_range.start);
|
||||
const column_end = (node.source_end - line_range.start);
|
||||
const column_start = (node.loc.start - line_range.start);
|
||||
const column_end = (node.loc.end - line_range.start);
|
||||
|
||||
try r.tty_config.setColor(writer, .white);
|
||||
try writer.writeByte('<');
|
||||
|
|
@ -271,10 +271,10 @@ fn writeColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !v
|
|||
}
|
||||
|
||||
fn writeLineColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
|
||||
const line_start = r.lines.calculateLine(node.source_start);
|
||||
const line_start = r.lines.calculateLine(node.loc.start);
|
||||
const line_range = r.lines.ranges.items[line_start];
|
||||
const column_start = (node.source_start - line_range.start);
|
||||
const column_end = (node.source_end - line_range.start);
|
||||
const column_start = (node.loc.start - line_range.start);
|
||||
const column_end = (node.loc.end - line_range.start);
|
||||
|
||||
try r.tty_config.setColor(writer, .white);
|
||||
try writer.writeByte('<');
|
||||
|
|
|
|||
628
src/Parse.zig
628
src/Parse.zig
|
|
@ -1,10 +1,9 @@
|
|||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const tok = @import("tokenizer.zig");
|
||||
const Ast = @import("Ast.zig");
|
||||
const assert = std.debug.assert;
|
||||
const Token = tok.Token;
|
||||
const Tokenizer = tok.Tokenizer;
|
||||
const Ast = @import("Ast.zig");
|
||||
|
||||
const Parse = @This();
|
||||
|
||||
gpa: std.mem.Allocator,
|
||||
|
|
@ -99,7 +98,7 @@ fn getTokenInfixType(tag: Token.Tag) Ast.Node.Tag {
|
|||
.star => .multiply_expr,
|
||||
.slash => .divide_expr,
|
||||
// .question_mark => .contains_expr,
|
||||
.equal => .assign_stmt,
|
||||
// .equal => .assign_stmt,
|
||||
.ampersand_ampersand, .keyword_and => .logical_and_expr,
|
||||
.pipe_pipe, .keyword_or => .logical_or_expr,
|
||||
.equal_equal => .logical_equality_expr,
|
||||
|
|
@ -165,7 +164,6 @@ fn checkTokenInSet(p: *const Parse, tag_set: []const Token.Tag) bool {
|
|||
|
||||
fn nextToken(p: *Parse) Token {
|
||||
assert(p.grammar_stack.items.len > 0);
|
||||
|
||||
const token = p.token;
|
||||
const context = p.grammar_stack.getLast();
|
||||
p.token = p.tokenizer.next(context.grammar);
|
||||
|
|
@ -252,6 +250,7 @@ fn nodeListFromScratch(p: *Parse, start_offset: usize, end_offset: usize) Error!
|
|||
|
||||
const span = end_offset - start_offset;
|
||||
assert(span > 0);
|
||||
|
||||
const list = try p.arena.alloc(*Ast.Node, span);
|
||||
defer p.scratch.shrinkRetainingCapacity(start_offset);
|
||||
|
||||
|
|
@ -261,7 +260,6 @@ fn nodeListFromScratch(p: *Parse, start_offset: usize, end_offset: usize) Error!
|
|||
list[li] = p.scratch.items[i];
|
||||
li += 1;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
@ -269,15 +267,14 @@ fn makeNodeSequence(
|
|||
p: *Parse,
|
||||
context: *const StmtContext,
|
||||
tag: Ast.Node.Tag,
|
||||
bytes_start: usize,
|
||||
bytes_end: usize,
|
||||
loc: Ast.Node.Span,
|
||||
scratch_offset: usize,
|
||||
) Error!*Ast.Node {
|
||||
var list: ?[]*Ast.Node = null;
|
||||
if (!p.isScratchEmpty(context)) {
|
||||
list = try p.nodeListFromScratch(scratch_offset, p.scratch.items.len);
|
||||
}
|
||||
return Ast.createListNode(p.arena, tag, bytes_start, bytes_end, list);
|
||||
return .createList(p.arena, tag, loc, list);
|
||||
}
|
||||
|
||||
fn isBlockStackEmpty(p: *Parse, context: *const StmtContext) bool {
|
||||
|
|
@ -337,23 +334,20 @@ fn collectBlock(p: *Parse, context: *StmtContext, level: usize) Error!?*Ast.Node
|
|||
const block = p.peekBlockStack(context);
|
||||
if (block.level < level) return null;
|
||||
|
||||
const bytes_start = block.source_offset;
|
||||
var bytes_end: usize = 0;
|
||||
const span_start = block.source_offset;
|
||||
var span_end: usize = 0;
|
||||
|
||||
if (!p.isScratchEmpty(context)) {
|
||||
const last = p.peekScratch(context);
|
||||
bytes_end = last.source_end;
|
||||
span_end = last.loc.end;
|
||||
} else {
|
||||
bytes_end = bytes_start;
|
||||
span_end = span_start;
|
||||
}
|
||||
|
||||
var node = try p.makeNodeSequence(
|
||||
context,
|
||||
.block_stmt,
|
||||
bytes_start,
|
||||
bytes_end,
|
||||
block.scratch_offset,
|
||||
);
|
||||
var node = try p.makeNodeSequence(context, .block_stmt, .{
|
||||
.start = span_start,
|
||||
.end = span_end,
|
||||
}, block.scratch_offset);
|
||||
node = try p.fixupBlock(context, node);
|
||||
_ = p.popBlockStack(context);
|
||||
return node;
|
||||
|
|
@ -407,13 +401,10 @@ fn collectContext(
|
|||
}
|
||||
}
|
||||
|
||||
const node = try p.makeNodeSequence(
|
||||
context,
|
||||
.choice_stmt,
|
||||
choice_state.source_offset,
|
||||
p.token.loc.start,
|
||||
choice_state.scratch_offset,
|
||||
);
|
||||
const node = try p.makeNodeSequence(context, .choice_stmt, .{
|
||||
.start = choice_state.source_offset,
|
||||
.end = p.token.loc.start,
|
||||
}, choice_state.scratch_offset);
|
||||
try p.scratch.append(p.gpa, node);
|
||||
}
|
||||
if (!should_gather) return p.collectBlock(context, level);
|
||||
|
|
@ -431,10 +422,11 @@ fn collectStitch(p: *Parse, context: *StmtContext) Error!?*Ast.Node {
|
|||
.function_prototype => .function_decl,
|
||||
else => return node,
|
||||
};
|
||||
const span_start = proto.source_start;
|
||||
const span_end = if (node) |n| n.source_end else proto.source_end;
|
||||
_ = p.popScratch(context);
|
||||
return Ast.createBinaryNode(p.arena, tag, span_start, span_end, proto, node);
|
||||
return .createBinary(p.arena, tag, .{
|
||||
.start = proto.loc.start,
|
||||
.end = if (node) |n| n.loc.end else proto.loc.end,
|
||||
}, proto, node);
|
||||
}
|
||||
|
||||
fn collectKnot(p: *Parse, context: *StmtContext) Error!?*Ast.Node {
|
||||
|
|
@ -449,10 +441,10 @@ fn collectKnot(p: *Parse, context: *StmtContext) Error!?*Ast.Node {
|
|||
const list = try p.nodeListFromScratch(p.knot_offset + 1, p.scratch.items.len);
|
||||
defer _ = p.popScratch(context);
|
||||
|
||||
const bytes_start = proto.source_start;
|
||||
const bytes_end = if (child) |n| n.source_end else proto.source_end;
|
||||
|
||||
return Ast.createKnotDeclNode(p.arena, .knot_decl, bytes_start, bytes_end, proto, list);
|
||||
return .createKnot(p.arena, .knot_decl, .{
|
||||
.start = proto.loc.start,
|
||||
.end = if (child) |n| n.loc.end else proto.loc.end,
|
||||
}, proto, list);
|
||||
}
|
||||
|
||||
fn handleChoiceBranch(p: *Parse, context: *StmtContext, node: *Ast.Node) !void {
|
||||
|
|
@ -462,14 +454,14 @@ fn handleChoiceBranch(p: *Parse, context: *StmtContext, node: *Ast.Node) !void {
|
|||
try p.block_stack.append(p.gpa, .{
|
||||
.level = 0,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.source_start,
|
||||
.source_offset = node.loc.start,
|
||||
});
|
||||
}
|
||||
if (p.isChoiceStackEmpty(context)) {
|
||||
try p.choice_stack.append(p.gpa, .{
|
||||
.level = level,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.source_start,
|
||||
.source_offset = node.loc.start,
|
||||
});
|
||||
} else {
|
||||
const choice_state = p.peekChoiceStack(context);
|
||||
|
|
@ -483,11 +475,10 @@ fn handleChoiceBranch(p: *Parse, context: *StmtContext, node: *Ast.Node) !void {
|
|||
.source_offset = p.token.loc.start,
|
||||
});
|
||||
}
|
||||
|
||||
try p.choice_stack.append(p.gpa, .{
|
||||
.level = level,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.source_start,
|
||||
.source_offset = node.loc.start,
|
||||
});
|
||||
} else if (level == choice_state.level) {
|
||||
const t_node = try p.collectBlock(context, level);
|
||||
|
|
@ -500,16 +491,15 @@ fn handleChoiceBranch(p: *Parse, context: *StmtContext, node: *Ast.Node) !void {
|
|||
}
|
||||
|
||||
fn handleGatherPoint(p: *Parse, context: *StmtContext, node: **Ast.Node) !void {
|
||||
const token = p.token;
|
||||
const main_token = p.token;
|
||||
const level = context.level;
|
||||
|
||||
if (p.isBlockStackEmpty(context)) {
|
||||
assert(p.isChoiceStackEmpty(context));
|
||||
|
||||
try p.block_stack.append(p.gpa, .{
|
||||
.level = 0,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.*.source_start,
|
||||
.source_offset = node.*.loc.start,
|
||||
});
|
||||
}
|
||||
// Gather points terminate compound statements at the appropriate level.
|
||||
|
|
@ -522,20 +512,16 @@ fn handleGatherPoint(p: *Parse, context: *StmtContext, node: **Ast.Node) !void {
|
|||
try p.block_stack.append(p.gpa, .{
|
||||
.level = choice_state.level,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.*.source_start,
|
||||
.source_offset = node.*.loc.start,
|
||||
});
|
||||
}
|
||||
} else if (!p.isScratchEmpty(context)) {
|
||||
const tmp = (try p.collectContext(context, level - 1, true)) orelse @panic("FUCK!");
|
||||
if (tmp.tag == .choice_stmt) {
|
||||
node.* = try Ast.createBinaryNode(
|
||||
p.arena,
|
||||
.gathered_stmt,
|
||||
tmp.source_start,
|
||||
token.loc.start,
|
||||
tmp,
|
||||
node.*,
|
||||
);
|
||||
node.* = try Ast.Node.createBinary(p.arena, .gathered_stmt, .{
|
||||
.start = tmp.loc.start,
|
||||
.end = main_token.loc.start,
|
||||
}, tmp, node.*);
|
||||
}
|
||||
if (!p.isBlockStackEmpty(context)) {
|
||||
const b = p.peekBlockStack(context);
|
||||
|
|
@ -553,7 +539,7 @@ fn handleContentStmt(p: *Parse, context: *StmtContext, node: *Ast.Node) !void {
|
|||
try p.block_stack.append(p.gpa, .{
|
||||
.level = 0,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.source_start,
|
||||
.source_offset = node.loc.start,
|
||||
});
|
||||
}
|
||||
if (!p.isChoiceStackEmpty(context)) {
|
||||
|
|
@ -564,7 +550,7 @@ fn handleContentStmt(p: *Parse, context: *StmtContext, node: *Ast.Node) !void {
|
|||
try p.block_stack.append(p.gpa, .{
|
||||
.level = choice_state.level,
|
||||
.scratch_offset = p.scratch.items.len,
|
||||
.source_offset = node.source_start,
|
||||
.source_offset = node.loc.start,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -600,10 +586,11 @@ fn expectExpr(p: *Parse) Error!*Ast.Node {
|
|||
}
|
||||
|
||||
fn parseAtom(p: *Parse, tag: Ast.Node.Tag) Error!*Ast.Node {
|
||||
const token = p.nextToken();
|
||||
const span_start = token.loc.start;
|
||||
const span_end = token.loc.end;
|
||||
return Ast.createLeafNode(p.arena, tag, span_start, span_end);
|
||||
const main_token = p.nextToken();
|
||||
return .createLeaf(p.arena, tag, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = main_token.loc.end,
|
||||
});
|
||||
}
|
||||
|
||||
fn parseIdentifier(p: *Parse) Error!*Ast.Node {
|
||||
|
|
@ -640,14 +627,15 @@ fn parsePrimaryExpr(p: *Parse) Error!?*Ast.Node {
|
|||
fn parsePrefixExpr(p: *Parse) Error!?*Ast.Node {
|
||||
switch (p.token.tag) {
|
||||
.keyword_not, .minus, .exclaimation_mark => {
|
||||
const token = p.nextToken();
|
||||
const main_token = p.nextToken();
|
||||
const lhs = try parsePrefixExpr(p);
|
||||
if (lhs == null) return null;
|
||||
|
||||
const tag = getTokenPrefixType(token.tag);
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = if (lhs) |n| n.source_end else p.token.loc.end;
|
||||
return Ast.createBinaryNode(p.arena, tag, bytes_start, bytes_end, lhs, null);
|
||||
const tag = getTokenPrefixType(main_token.tag);
|
||||
return .createBinary(p.arena, tag, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = if (lhs) |n| n.loc.end else p.token.loc.end,
|
||||
}, lhs, null);
|
||||
},
|
||||
else => return parsePrimaryExpr(p),
|
||||
}
|
||||
|
|
@ -673,10 +661,10 @@ fn parseInfixExpr(
|
|||
next_node = try parseInfixExpr(p, null, token_precedence);
|
||||
if (next_node) |rhs| {
|
||||
const tag = getTokenInfixType(token.tag);
|
||||
const bytes_start = if (lhs) |n| n.source_start else token.loc.start;
|
||||
const bytes_end = rhs.source_end;
|
||||
|
||||
lhs = try Ast.createBinaryNode(p.arena, tag, bytes_start, bytes_end, lhs, rhs);
|
||||
lhs = try Ast.Node.createBinary(p.arena, tag, .{
|
||||
.start = if (lhs) |n| n.loc.start else token.loc.start,
|
||||
.end = rhs.loc.end,
|
||||
}, lhs, rhs);
|
||||
} else return null;
|
||||
} else break;
|
||||
}
|
||||
|
|
@ -689,7 +677,7 @@ fn parseExpression(p: *Parse) Error!?*Ast.Node {
|
|||
|
||||
fn parseStringExpr(p: *Parse) Error!*Ast.Node {
|
||||
assert(p.token.tag == .double_quote);
|
||||
const leading_token = p.nextToken();
|
||||
const main_token = p.nextToken();
|
||||
|
||||
while (true) switch (p.token.tag) {
|
||||
.double_quote, .newline, .eof => break,
|
||||
|
|
@ -697,34 +685,42 @@ fn parseStringExpr(p: *Parse) Error!*Ast.Node {
|
|||
};
|
||||
|
||||
const last_token = try p.expectToken(.double_quote, true);
|
||||
const span_start = leading_token.loc.start;
|
||||
const span_end = p.token.loc.start;
|
||||
const expr = try Ast.createLeafNode(p.arena, .string_literal, leading_token.loc.end, last_token.loc.start);
|
||||
return Ast.createBinaryNode(p.arena, .string_expr, span_start, span_end, expr, null);
|
||||
const expr = try Ast.Node.createLeaf(p.arena, .string_literal, .{
|
||||
.start = main_token.loc.end,
|
||||
.end = last_token.loc.start,
|
||||
});
|
||||
return .createBinary(p.arena, .string_expr, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, expr, null);
|
||||
}
|
||||
|
||||
fn parseContentString(p: *Parse, token_set: []const Token.Tag) Error!?*Ast.Node {
|
||||
const main_token = p.token;
|
||||
while (!p.checkTokenInSet(token_set)) _ = p.nextToken();
|
||||
|
||||
const span_start = main_token.loc.start;
|
||||
const span_end = p.token.loc.start;
|
||||
const tag: Ast.Node.Tag = if (span_start == span_end) .empty_string else .string_literal;
|
||||
return Ast.createLeafNode(p.arena, tag, span_start, span_end);
|
||||
return .createLeaf(p.arena, if (main_token.loc.start == p.token.loc.start)
|
||||
.empty_string
|
||||
else
|
||||
.string_literal, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
});
|
||||
}
|
||||
|
||||
fn parseExprStmt(p: *Parse, lhs: ?*Ast.Node) Error!*Ast.Node {
|
||||
const token = p.token;
|
||||
const main_token = p.token;
|
||||
const node = try parseInfixExpr(p, lhs, .none);
|
||||
_ = try p.expectNewline();
|
||||
|
||||
const bytes_start = if (lhs) |n| n.source_start else token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
return Ast.createBinaryNode(p.arena, .expr_stmt, bytes_start, bytes_end, node, null);
|
||||
return .createBinary(p.arena, .expr_stmt, .{
|
||||
.start = if (lhs) |n| n.loc.start else main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseAssignStmt(p: *Parse) Error!*Ast.Node {
|
||||
const token = p.token;
|
||||
const main_token = p.token;
|
||||
const lhs = try parseIdentifierExpr(p);
|
||||
|
||||
if (!p.checkToken(.equal)) return parseExprStmt(p, lhs);
|
||||
|
|
@ -733,21 +729,24 @@ fn parseAssignStmt(p: *Parse) Error!*Ast.Node {
|
|||
const rhs = try p.expectExpr();
|
||||
_ = try p.expectNewline();
|
||||
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
return Ast.createBinaryNode(p.arena, .assign_stmt, bytes_start, bytes_end, lhs, rhs);
|
||||
return .createBinary(p.arena, .assign_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
}
|
||||
|
||||
fn parseTempDecl(p: *Parse) Error!*Ast.Node {
|
||||
const token = p.nextToken();
|
||||
const main_token = p.nextToken();
|
||||
const lhs = try p.expectIdentifier();
|
||||
_ = try p.expectToken(.equal, true);
|
||||
|
||||
const rhs = try p.expectExpr();
|
||||
_ = try p.expectNewline();
|
||||
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
return Ast.createBinaryNode(p.arena, .temp_decl, bytes_start, bytes_end, lhs, rhs);
|
||||
return .createBinary(p.arena, .temp_decl, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
}
|
||||
|
||||
fn parseTildeStmt(p: *Parse) Error!*Ast.Node {
|
||||
|
|
@ -755,7 +754,7 @@ fn parseTildeStmt(p: *Parse) Error!*Ast.Node {
|
|||
defer p.popGrammar();
|
||||
|
||||
_ = p.nextToken();
|
||||
const node: *Ast.Node = switch (p.token.tag) {
|
||||
const node = switch (p.token.tag) {
|
||||
.keyword_temp => try parseTempDecl(p),
|
||||
.keyword_return => try parseReturnStmt(p),
|
||||
.identifier => try parseAssignStmt(p),
|
||||
|
|
@ -766,17 +765,17 @@ fn parseTildeStmt(p: *Parse) Error!*Ast.Node {
|
|||
|
||||
fn parseReturnStmt(p: *Parse) Error!*Ast.Node {
|
||||
var node: ?*Ast.Node = null;
|
||||
const token = p.nextToken();
|
||||
const main_token = p.nextToken();
|
||||
|
||||
if (!p.checkToken(.newline) and !p.checkToken(.eof)) {
|
||||
node = try parseInfixExpr(p, null, .none);
|
||||
}
|
||||
|
||||
_ = try p.expectNewline();
|
||||
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
|
||||
return Ast.createBinaryNode(p.arena, .return_stmt, bytes_start, bytes_end, node, null);
|
||||
return .createBinary(p.arena, .return_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseIdentifierExpr(p: *Parse) Error!*Ast.Node {
|
||||
|
|
@ -787,97 +786,44 @@ fn parseIdentifierExpr(p: *Parse) Error!*Ast.Node {
|
|||
.dot => {
|
||||
_ = p.nextToken();
|
||||
const rhs = try p.expectIdentifier();
|
||||
const bytes_start = lhs.source_start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
|
||||
lhs = try Ast.createBinaryNode(
|
||||
p.arena,
|
||||
.selector_expr,
|
||||
bytes_start,
|
||||
bytes_end,
|
||||
lhs,
|
||||
rhs,
|
||||
);
|
||||
lhs = try Ast.Node.createBinary(p.arena, .selector_expr, .{
|
||||
.start = lhs.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
},
|
||||
.left_paren => {
|
||||
const rhs = try parseArgumentList(p);
|
||||
const bytes_start = lhs.source_start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
|
||||
return Ast.createBinaryNode(
|
||||
p.arena,
|
||||
.call_expr,
|
||||
bytes_start,
|
||||
bytes_end,
|
||||
lhs,
|
||||
rhs,
|
||||
);
|
||||
return .createBinary(p.arena, .call_expr, .{
|
||||
.start = lhs.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
},
|
||||
else => return lhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
fn parseContentExpr(p: *Parse, token_set: []const Token.Tag) Error!?*Ast.Node {
|
||||
|
||||
fn parseDivertExpr(p: *Parse) Error!*Ast.Node {
|
||||
const main_token = p.nextToken();
|
||||
const node = try parseIdentifierExpr(p);
|
||||
return .createBinary(p.arena, .divert_expr, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseDivertStmt(p: *Parse) Error!*Ast.Node {
|
||||
try p.pushGrammar(.expression);
|
||||
defer p.popGrammar();
|
||||
|
||||
const main_token = p.token;
|
||||
const context = makeStmtContext(p, .block, null);
|
||||
const node = try parseDivertExpr(p);
|
||||
_ = try p.expectNewline();
|
||||
|
||||
while (true) {
|
||||
var node: ?*Ast.Node = null;
|
||||
if (!p.checkTokenInSet(token_set)) {
|
||||
node = try parseContentString(p, token_set);
|
||||
} else switch (p.token.tag) {
|
||||
.eof, .newline, .right_brace => break,
|
||||
// .left_brace => node = try parseLbraceExpr(p),
|
||||
// .right_arrow => node = try parseDivertStmt(p),
|
||||
//.INK_TT_GLUE => node = ink_parse_glue(p),
|
||||
else => {
|
||||
return p.fail(.unexpected_token, p.token);
|
||||
},
|
||||
}
|
||||
if (node) |n| try p.scratch.append(p.gpa, n);
|
||||
}
|
||||
|
||||
const span_start = main_token.loc.start;
|
||||
const span_end = p.token.loc.start;
|
||||
return p.makeNodeSequence(&context, .content, span_start, span_end, context.scratch_top);
|
||||
}
|
||||
|
||||
fn parseArgumentList(p: *Parse) Error!?*Ast.Node {
|
||||
const context = p.makeStmtContext(.block, null);
|
||||
const token = try p.expectToken(.left_paren, true);
|
||||
|
||||
if (!p.checkToken(.right_paren)) {
|
||||
var cnt: usize = 0;
|
||||
while (true) : (cnt += 1) {
|
||||
if (cnt == p.max_argument_count) {
|
||||
return p.fail(.too_many_arguments, p.token);
|
||||
}
|
||||
|
||||
const node = try parseInfixExpr(p, null, .none);
|
||||
if (node) |n| try p.scratch.append(p.gpa, n);
|
||||
if (p.checkToken(.comma)) {
|
||||
_ = p.nextToken();
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
_ = try p.expectToken(.right_paren, false);
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
return p.makeNodeSequence(&context, .argument_list, bytes_start, bytes_end, context.scratch_top);
|
||||
}
|
||||
|
||||
fn parseContentStmt(p: *Parse) Error!*Ast.Node {
|
||||
const token_set = [_]Token.Tag{
|
||||
.left_brace, .right_brace, .right_arrow,
|
||||
.glue, .newline, .eof,
|
||||
};
|
||||
const main_token = p.token;
|
||||
const node = try parseContentExpr(p, &token_set);
|
||||
const end_token = try p.expectNewline();
|
||||
const span_start = main_token.loc.start;
|
||||
const span_end = end_token.loc.start;
|
||||
return Ast.createBinaryNode(p.arena, .content_stmt, span_start, span_end, node, null);
|
||||
return .createBinary(p.arena, .divert_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseChoiceExpr(p: *Parse) Error!?*Ast.Node {
|
||||
|
|
@ -886,7 +832,7 @@ fn parseChoiceExpr(p: *Parse) Error!?*Ast.Node {
|
|||
.right_bracket, .right_arrow, .newline,
|
||||
.eof,
|
||||
};
|
||||
const token = p.token;
|
||||
const main_token = p.token;
|
||||
var lhs: ?*Ast.Node = null;
|
||||
var mhs: ?*Ast.Node = null;
|
||||
var rhs: ?*Ast.Node = null;
|
||||
|
|
@ -920,50 +866,286 @@ fn parseChoiceExpr(p: *Parse) Error!?*Ast.Node {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
return Ast.createChoiceExprNode(p.arena, .choice_expr, bytes_start, bytes_end, lhs, mhs, rhs);
|
||||
return .createChoice(p.arena, .choice_expr, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, mhs, rhs);
|
||||
}
|
||||
|
||||
fn parseChoiceStmt(p: *Parse, context: *StmtContext) Error!*Ast.Node {
|
||||
const token = p.token;
|
||||
const level = p.eatTokenLooped(token.tag, true);
|
||||
const main_token = p.token;
|
||||
const level = p.eatTokenLooped(main_token.tag, true);
|
||||
const node = try parseChoiceExpr(p);
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = if (node) |n| n.source_end else p.token.loc.start;
|
||||
|
||||
const span_end = if (node) |n| n.loc.end else p.token.loc.start;
|
||||
context.level = level;
|
||||
|
||||
if (p.checkToken(.newline)) _ = p.nextToken();
|
||||
const tag = getBranchTag(token.tag);
|
||||
return Ast.createBinaryNode(p.arena, tag, bytes_start, bytes_end, node, null);
|
||||
|
||||
return .createBinary(p.arena, getBranchTag(main_token.tag), .{
|
||||
.start = main_token.loc.start,
|
||||
.end = span_end,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseGatherPointStmt(p: *Parse, context: *StmtContext) Error!*Ast.Node {
|
||||
const token = p.token;
|
||||
const level = p.eatTokenLooped(token.tag, true);
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = p.token.loc.start;
|
||||
|
||||
const main_token = p.token;
|
||||
const level = p.eatTokenLooped(main_token.tag, true);
|
||||
const span_end = p.token.loc.start;
|
||||
context.level = level;
|
||||
|
||||
return Ast.createBinaryNode(p.arena, .gather_point_stmt, bytes_start, bytes_end, null, null);
|
||||
p.eatToken(.whitespace);
|
||||
p.eatToken(.newline);
|
||||
return .createBinary(p.arena, .gather_point_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = span_end,
|
||||
}, null, null);
|
||||
}
|
||||
|
||||
fn parseConditional(p: *Parse, main_token: Token, expr: ?*Ast.Node) Error!?*Ast.Node {
|
||||
var context = p.makeStmtContext(.conditional, expr);
|
||||
p.eatToken(.whitespace);
|
||||
|
||||
while (!p.checkToken(.eof) and !p.checkToken(.right_brace)) {
|
||||
const node = parseStmt(p, &context) catch |err| switch (err) {
|
||||
error.ParseError => {
|
||||
if (p.panic_mode) p.synchronize();
|
||||
p.eatToken(.newline);
|
||||
continue;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try p.scratch.append(p.gpa, node);
|
||||
}
|
||||
|
||||
const end_token = try p.expectToken(.right_brace, true);
|
||||
const node = try p.collectContext(&context, 0, false);
|
||||
if (node) |n| try p.scratch.append(p.gpa, n);
|
||||
|
||||
const list = try p.nodeListFromScratch(context.scratch_top, p.scratch.items.len);
|
||||
return .createSwitch(p.arena, if (expr != null and !context.is_block_created)
|
||||
.switch_stmt
|
||||
else if (expr == null and !context.is_block_created)
|
||||
.multi_if_stmt
|
||||
else
|
||||
.if_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = end_token.loc.start,
|
||||
}, expr, list);
|
||||
}
|
||||
|
||||
fn parseInlineIf(p: *Parse, main_token: Token, lhs: ?*Ast.Node) Error!?*Ast.Node {
|
||||
const token_set = [_]Token.Tag{
|
||||
.left_brace, .right_brace, .right_arrow,
|
||||
.glue, .newline, .eof,
|
||||
};
|
||||
const scratch_top = p.scratch.items.len;
|
||||
|
||||
p.eatToken(.whitespace);
|
||||
|
||||
const content_node = try parseContentExpr(p, &token_set);
|
||||
const end_token = try p.expectToken(.right_brace, true);
|
||||
if (content_node) |n| try p.scratch.append(p.gpa, n);
|
||||
|
||||
const list = try p.nodeListFromScratch(scratch_top, p.scratch.items.len);
|
||||
return try .createSwitch(p.arena, .if_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = end_token.loc.end,
|
||||
}, lhs, list);
|
||||
}
|
||||
|
||||
fn parseLbraceExpr(p: *Parse) Error!?*Ast.Node {
|
||||
const lbrace_token = p.token;
|
||||
const lhs = n: {
|
||||
try p.pushGrammar(.expression);
|
||||
defer p.popGrammar();
|
||||
|
||||
_ = p.nextToken();
|
||||
const node = try parseExpression(p);
|
||||
break :n node;
|
||||
};
|
||||
if (lhs == null) {
|
||||
try p.pushGrammar(.content);
|
||||
defer p.popGrammar();
|
||||
|
||||
_ = try p.expectToken(.newline, true);
|
||||
return parseConditional(p, lbrace_token, null);
|
||||
}
|
||||
if (p.checkToken(.right_brace)) {
|
||||
const rbrace_token = p.nextToken();
|
||||
return .createBinary(p.arena, .inline_logic_expr, .{
|
||||
.start = lbrace_token.loc.start,
|
||||
.end = rbrace_token.loc.end,
|
||||
}, lhs, null);
|
||||
}
|
||||
_ = try p.expectToken(.colon, true);
|
||||
|
||||
if (p.checkToken(.newline)) {
|
||||
_ = p.nextToken();
|
||||
return parseConditional(p, lbrace_token, lhs);
|
||||
} else {
|
||||
_ = p.nextToken();
|
||||
return parseInlineIf(p, lbrace_token, lhs);
|
||||
}
|
||||
}
|
||||
|
||||
fn parseContentExpr(p: *Parse, token_set: []const Token.Tag) Error!?*Ast.Node {
|
||||
const main_token = p.token;
|
||||
const context = makeStmtContext(p, .block, null);
|
||||
|
||||
while (true) {
|
||||
var node: ?*Ast.Node = null;
|
||||
if (!p.checkTokenInSet(token_set)) {
|
||||
node = try parseContentString(p, token_set);
|
||||
} else switch (p.token.tag) {
|
||||
.eof, .newline, .right_brace => break,
|
||||
.left_brace => node = try parseLbraceExpr(p),
|
||||
.right_arrow => node = try parseDivertStmt(p),
|
||||
//.INK_TT_GLUE => node = ink_parse_glue(p),
|
||||
else => {
|
||||
return p.fail(.unexpected_token, p.token);
|
||||
},
|
||||
}
|
||||
if (node) |n| try p.scratch.append(p.gpa, n);
|
||||
}
|
||||
return p.makeNodeSequence(&context, .content, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, context.scratch_top);
|
||||
}
|
||||
|
||||
fn parseContentStmt(p: *Parse) Error!*Ast.Node {
|
||||
const token_set = [_]Token.Tag{
|
||||
.left_brace, .right_brace, .right_arrow,
|
||||
.glue, .newline, .eof,
|
||||
};
|
||||
const main_token = p.token;
|
||||
const node = try parseContentExpr(p, &token_set);
|
||||
const end_token = try p.expectNewline();
|
||||
return .createBinary(p.arena, .content_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = end_token.loc.start,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseParameterDecl(p: *Parse) Error!*Ast.Node {
|
||||
const tag: Ast.Node.Tag = if (p.checkToken(.keyword_ref)) blk: {
|
||||
_ = p.nextToken();
|
||||
break :blk .ref_parameter_decl;
|
||||
} else .parameter_decl;
|
||||
|
||||
const node = try p.expectIdentifier();
|
||||
node.tag = tag;
|
||||
return node;
|
||||
}
|
||||
|
||||
fn parseParameterList(p: *Parse) Error!?*Ast.Node {
|
||||
const context = p.makeStmtContext(.block, null);
|
||||
const main_token = try p.expectToken(.left_paren, true);
|
||||
|
||||
if (!p.checkToken(.right_paren)) {
|
||||
var cnt: usize = 0;
|
||||
while (true) : (cnt += 1) {
|
||||
if (cnt == p.max_argument_count) {
|
||||
return p.fail(.too_many_parameters, p.token);
|
||||
}
|
||||
|
||||
const node = try parseParameterDecl(p);
|
||||
try p.scratch.append(p.gpa, node);
|
||||
|
||||
if (p.checkToken(.comma)) {
|
||||
_ = p.nextToken();
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
_ = try p.expectToken(.right_paren, true);
|
||||
return p.makeNodeSequence(&context, .parameter_list, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, context.scratch_top);
|
||||
}
|
||||
|
||||
fn parseArgumentList(p: *Parse) Error!?*Ast.Node {
|
||||
const context = p.makeStmtContext(.block, null);
|
||||
const main_token = try p.expectToken(.left_paren, true);
|
||||
|
||||
if (!p.checkToken(.right_paren)) {
|
||||
var cnt: usize = 0;
|
||||
while (true) : (cnt += 1) {
|
||||
if (cnt == p.max_argument_count) {
|
||||
return p.fail(.too_many_arguments, p.token);
|
||||
}
|
||||
|
||||
const node = try parseInfixExpr(p, null, .none);
|
||||
if (node) |n| try p.scratch.append(p.gpa, n);
|
||||
if (p.checkToken(.comma)) {
|
||||
_ = p.nextToken();
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
_ = try p.expectToken(.right_paren, false);
|
||||
return p.makeNodeSequence(&context, .argument_list, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, context.scratch_top);
|
||||
}
|
||||
|
||||
fn parseConditionalBranch(p: *Parse, tag: Ast.Node.Tag) Error!?*Ast.Node {
|
||||
const main_token = p.token;
|
||||
var node_tag = tag;
|
||||
var node: ?*Ast.Node = null;
|
||||
|
||||
if (p.checkToken(.keyword_else)) {
|
||||
_ = p.nextToken();
|
||||
node_tag = .else_branch;
|
||||
} else {
|
||||
node = try parseExpression(p);
|
||||
if (node == null) return null;
|
||||
}
|
||||
if (!p.checkToken(.colon)) return null;
|
||||
_ = p.nextToken();
|
||||
if (p.checkToken(.newline)) _ = p.nextToken();
|
||||
|
||||
return .createBinary(p.arena, node_tag, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, node, null);
|
||||
}
|
||||
|
||||
fn parseConditionalStmt(p: *Parse, context: *StmtContext) Error!*Ast.Node {
|
||||
try p.pushGrammar(.expression);
|
||||
defer p.popGrammar();
|
||||
_ = p.nextToken();
|
||||
|
||||
const node = try parseConditionalBranch(p, if (context.expression_node) |_|
|
||||
.switch_case
|
||||
else
|
||||
.if_branch);
|
||||
if (node) |n| return n;
|
||||
|
||||
p.rewindGrammar();
|
||||
try p.pushGrammar(.content);
|
||||
defer p.popGrammar();
|
||||
|
||||
_ = p.nextToken();
|
||||
return parseGatherPointStmt(p, context);
|
||||
}
|
||||
|
||||
fn parseVar(p: *Parse, tag: Ast.Node.Tag) Error!*Ast.Node {
|
||||
try p.pushGrammar(.expression);
|
||||
defer p.popGrammar();
|
||||
|
||||
const token = p.nextToken();
|
||||
const main_token = p.nextToken();
|
||||
const lhs = try p.expectIdentifier();
|
||||
_ = try p.expectToken(.equal, true);
|
||||
|
||||
const rhs = try p.expectExpr();
|
||||
const last_token = try p.expectNewline();
|
||||
const bytes_start = token.loc.start;
|
||||
const bytes_end = last_token.loc.start;
|
||||
return Ast.createBinaryNode(p.arena, tag, bytes_start, bytes_end, lhs, rhs);
|
||||
return .createBinary(p.arena, tag, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = last_token.loc.start,
|
||||
}, lhs, rhs);
|
||||
}
|
||||
|
||||
fn parseVarDecl(p: *Parse) Error!*Ast.Node {
|
||||
|
|
@ -976,6 +1158,43 @@ fn parseConstDecl(p: *Parse) Error!*Ast.Node {
|
|||
return parseVar(p, .const_decl);
|
||||
}
|
||||
|
||||
fn parseKnotDecl(p: *Parse) Error!*Ast.Node {
|
||||
var tag: Ast.Node.Tag = .stitch_prototype;
|
||||
var lhs: ?*Ast.Node = null;
|
||||
var rhs: ?*Ast.Node = null;
|
||||
const main_token = p.nextToken();
|
||||
|
||||
try p.pushGrammar(.expression);
|
||||
defer p.popGrammar();
|
||||
|
||||
p.eatToken(.whitespace);
|
||||
if (p.checkToken(.equal)) {
|
||||
tag = .knot_prototype;
|
||||
|
||||
while (p.checkToken(.equal)) {
|
||||
_ = p.nextToken();
|
||||
}
|
||||
}
|
||||
if (p.checkToken(.keyword_function)) {
|
||||
_ = p.nextToken();
|
||||
tag = .function_prototype;
|
||||
}
|
||||
|
||||
lhs = try p.expectIdentifier();
|
||||
if (p.checkToken(.left_paren)) {
|
||||
rhs = try parseParameterList(p);
|
||||
}
|
||||
while (p.checkToken(.equal) or p.checkToken(.equal_equal)) {
|
||||
_ = p.nextToken();
|
||||
}
|
||||
|
||||
_ = try p.expectNewline();
|
||||
return .createBinary(p.arena, tag, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
}
|
||||
|
||||
fn parseStmt(p: *Parse, context: *StmtContext) Error!*Ast.Node {
|
||||
p.eatToken(.whitespace);
|
||||
|
||||
|
|
@ -983,15 +1202,14 @@ fn parseStmt(p: *Parse, context: *StmtContext) Error!*Ast.Node {
|
|||
.star, .plus => try parseChoiceStmt(p, context),
|
||||
.minus => switch (context.tag) {
|
||||
.block => try parseGatherPointStmt(p, context),
|
||||
else => unreachable,
|
||||
//.conditional => try parseConditionalStmt(p, context),
|
||||
.conditional => try parseConditionalStmt(p, context),
|
||||
},
|
||||
.equal, .equal_equal => switch (context.tag) {
|
||||
//.block => try parseKnotDecl(p),
|
||||
.block => try parseKnotDecl(p),
|
||||
else => try parseContentStmt(p),
|
||||
},
|
||||
.tilde => try parseTildeStmt(p),
|
||||
//.right_arrow => try parseDivertStmt(p),
|
||||
.right_arrow => try parseDivertStmt(p),
|
||||
.right_brace => {
|
||||
const token = p.nextToken();
|
||||
return p.fail(.unexpected_token, token);
|
||||
|
|
@ -1022,12 +1240,11 @@ pub fn parseFile(p: *Parse) Error!*Ast.Node {
|
|||
try p.pushGrammar(.content);
|
||||
defer p.popGrammar();
|
||||
|
||||
const token = p.nextToken();
|
||||
const main_token = p.nextToken();
|
||||
while (!p.checkToken(.eof)) {
|
||||
const node = parseStmt(p, &context) catch |err| switch (err) {
|
||||
error.ParseError => {
|
||||
if (p.panic_mode) p.synchronize();
|
||||
|
||||
p.eatToken(.newline);
|
||||
continue;
|
||||
},
|
||||
|
|
@ -1039,7 +1256,8 @@ pub fn parseFile(p: *Parse) Error!*Ast.Node {
|
|||
const node = try p.collectKnot(&context);
|
||||
if (node) |n| try p.scratch.append(p.gpa, n);
|
||||
|
||||
const span_start = token.loc.start;
|
||||
const span_end = p.token.loc.end;
|
||||
return p.makeNodeSequence(&context, .file, span_start, span_end, context.scratch_top);
|
||||
return p.makeNodeSequence(&context, .file, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.end,
|
||||
}, context.scratch_top);
|
||||
}
|
||||
|
|
|
|||
19
src/main.zig
19
src/main.zig
|
|
@ -31,11 +31,25 @@ fn mainArgs(
|
|||
) !void {
|
||||
var source_path: ?[]const u8 = null;
|
||||
var arg_index: usize = 1;
|
||||
var compile_only: bool = false;
|
||||
var dump_ast: bool = false;
|
||||
var use_stdin: bool = false;
|
||||
var use_color: bool = false;
|
||||
|
||||
while (arg_index < args_list.len) : (arg_index += 1) {
|
||||
const arg = args_list[arg_index];
|
||||
if (std.mem.startsWith(u8, arg, "-")) {
|
||||
// TODO: Parse CLI options.
|
||||
if (std.mem.eql(u8, arg, "--stdin")) {
|
||||
use_stdin = true;
|
||||
} else if (std.mem.eql(u8, arg, "--compile-only")) {
|
||||
compile_only = true;
|
||||
} else if (std.mem.eql(u8, arg, "--dump-ast")) {
|
||||
dump_ast = true;
|
||||
} else if (std.mem.eql(u8, arg, "--use-color")) {
|
||||
use_color = true;
|
||||
} else {
|
||||
fatal("invalid parameter: '{s}'", .{arg});
|
||||
}
|
||||
} else if (source_path == null) {
|
||||
source_path = arg;
|
||||
} else {
|
||||
|
|
@ -62,7 +76,8 @@ fn mainArgs(
|
|||
var stdout_writer = stdout.writer(&stdout_buffer);
|
||||
|
||||
var story = try ink.Story.loadFromString(gpa, source_bytes, .{
|
||||
.stream_writer = &stdout_writer.interface,
|
||||
.dump_writer = &stdout_writer.interface,
|
||||
.dump_use_color = use_color,
|
||||
});
|
||||
defer story.deinit();
|
||||
}
|
||||
|
|
|
|||
12
src/root.zig
12
src/root.zig
|
|
@ -4,8 +4,8 @@ pub const Ast = @import("Ast.zig");
|
|||
|
||||
pub const Story = struct {
|
||||
pub const LoadOptions = struct {
|
||||
stream_writer: *std.Io.Writer,
|
||||
use_color: bool = true,
|
||||
dump_writer: *std.Io.Writer,
|
||||
dump_use_color: bool = true,
|
||||
};
|
||||
|
||||
pub fn loadFromString(
|
||||
|
|
@ -20,12 +20,12 @@ pub const Story = struct {
|
|||
var ast = try Ast.parse(gpa, arena, source_bytes, "<STDIN>", 0);
|
||||
defer ast.deinit(gpa);
|
||||
|
||||
try ast.render(gpa, options.stream_writer, .{
|
||||
.use_color = options.use_color,
|
||||
try ast.render(gpa, options.dump_writer, .{
|
||||
.use_color = options.dump_use_color,
|
||||
});
|
||||
if (ast.errors.len > 0) {
|
||||
try ast.renderErrors(gpa, options.stream_writer, .{
|
||||
.use_color = options.use_color,
|
||||
try ast.renderErrors(gpa, options.dump_writer, .{
|
||||
.use_color = options.dump_use_color,
|
||||
});
|
||||
return error.Invalid;
|
||||
}
|
||||
|
|
|
|||
9
testing/regression/CMakeLists.txt
Normal file
9
testing/regression/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
set(LIT_CFG_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
configure_file(lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py @ONLY)
|
||||
|
||||
find_program(LLVM_LIT_EXECUTABLE NAMES llvm-lit lit)
|
||||
|
||||
add_custom_target(check
|
||||
COMMAND ${LLVM_LIT_EXECUTABLE} -v "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
14
testing/regression/lit.cfg.py
Normal file
14
testing/regression/lit.cfg.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import lit.formats
|
||||
|
||||
config.name = "Ink Compiler Regression Tests"
|
||||
config.suffixes = [".ink"]
|
||||
config.tools = ["FileCheck"]
|
||||
config.test_format = lit.formats.ShTest(execute_external=True)
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
config.test_exec_root = os.path.join(config.project_build_root, "testing", "regression")
|
||||
exe_path = os.path.join(config.project_zig_root, "bin", "inkc")
|
||||
|
||||
config.substitutions.append(("%ink-compiler", exe_path))
|
||||
8
testing/regression/lit.site.cfg.py.in
Normal file
8
testing/regression/lit.site.cfg.py.in
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import os
|
||||
|
||||
config.project_source_root = r"@CMAKE_SOURCE_DIR@"
|
||||
config.project_build_root = r"@CMAKE_BINARY_DIR@"
|
||||
config.project_zig_root = os.path.join(r"@CMAKE_SOURCE_DIR@", "zig-out")
|
||||
|
||||
lit_config.load_config(
|
||||
config, os.path.join(config.project_source_root, "testing", "regression", "lit.cfg.py"))
|
||||
11
testing/regression/syntax/choice-branch-mixed.ink
Normal file
11
testing/regression/syntax/choice-branch-mixed.ink
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:11, line:11>
|
||||
// CHECK-NEXT: `--ChoiceStmt <line:11, line:11>
|
||||
// CHECK-NEXT: `--ChoiceStarStmt <line:11, col:1:7>
|
||||
// CHECK-NEXT: `--ChoiceContentExpr <col:3, col:7>
|
||||
// CHECK-NEXT: |--ChoiceStartContentExpr `A` <col:3, col:4>
|
||||
// CHECK-NEXT: `--ChoiceInnerContentExpr `B` <col:6, col:7>
|
||||
|
||||
* A[]B
|
||||
26
testing/regression/syntax/choice-nesting-normalize.ink
Normal file
26
testing/regression/syntax/choice-nesting-normalize.ink
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:22, line:26>
|
||||
// CHECK-NEXT: `--ChoiceStmt <line:22, line:26>
|
||||
// CHECK-NEXT: |--ChoiceStarStmt <line:22, col:1:8>
|
||||
// CHECK-NEXT: | `--ChoiceContentExpr <col:7, col:8>
|
||||
// CHECK-NEXT: | `--ChoiceStartContentExpr `A` <col:7, col:8>
|
||||
// CHECK-NEXT: |--ChoiceStarStmt <line:23, col:1:7>
|
||||
// CHECK-NEXT: | `--ChoiceContentExpr <col:6, col:7>
|
||||
// CHECK-NEXT: | `--ChoiceStartContentExpr `B` <col:6, col:7>
|
||||
// CHECK-NEXT: |--ChoiceStarStmt <line:24, col:1:6>
|
||||
// CHECK-NEXT: | `--ChoiceContentExpr <col:5, col:6>
|
||||
// CHECK-NEXT: | `--ChoiceStartContentExpr `C` <col:5, col:6>
|
||||
// CHECK-NEXT: |--ChoiceStarStmt <line:25, col:1:5>
|
||||
// CHECK-NEXT: | `--ChoiceContentExpr <col:4, col:5>
|
||||
// CHECK-NEXT: | `--ChoiceStartContentExpr `D` <col:4, col:5>
|
||||
// CHECK-NEXT: `--ChoiceStarStmt <line:26, col:1:4>
|
||||
// CHECK-NEXT: `--ChoiceContentExpr <col:3, col:4>
|
||||
// CHECK-NEXT: `--ChoiceStartContentExpr `E` <col:3, col:4>
|
||||
|
||||
***** A
|
||||
**** B
|
||||
*** C
|
||||
** D
|
||||
* E
|
||||
27
testing/regression/syntax/conditional-logical-and.ink
Normal file
27
testing/regression/syntax/conditional-logical-and.ink
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:23, line:27>
|
||||
// CHECK-NEXT: |--TempDecl <line:23, col:3:13>
|
||||
// CHECK-NEXT: | |--Identifier `x` <col:8, col:9>
|
||||
// CHECK-NEXT: | `--NumberLiteral `2` <col:12, col:13>
|
||||
// CHECK-NEXT: `--ContentStmt <line:25, col:1:48>
|
||||
// CHECK-NEXT: `--Content <col:1, col:48>
|
||||
// CHECK-NEXT: `--IfStmt <line:25, line:27>
|
||||
// CHECK-NEXT: |--LogicalAndExpr <col:2, col:20>
|
||||
// CHECK-NEXT: | |--LogicalGreaterThanOrEqualExpr <col:2, col:8>
|
||||
// CHECK-NEXT: | | |--Identifier `x` <col:2, col:3>
|
||||
// CHECK-NEXT: | | `--NumberLiteral `1` <col:7, col:8>
|
||||
// CHECK-NEXT: | `--LogicalLesserThanOrEqualExpr <col:13, col:20>
|
||||
// CHECK-NEXT: | |--Identifier `x` <col:13, col:14>
|
||||
// CHECK-NEXT: | `--NumberLiteral `10` <col:18, col:20>
|
||||
// CHECK-NEXT: `--BlockStmt <line:26, line:26>
|
||||
// CHECK-NEXT: `--ContentStmt <line:26, col:5:25>
|
||||
// CHECK-NEXT: `--Content <col:5, col:25>
|
||||
// CHECK-NEXT: `--StringLiteral `Between one and ten!` <col:5, col:25>
|
||||
|
||||
~ temp x = 2
|
||||
|
||||
{x >= 1 and x <= 10:
|
||||
Between one and ten!
|
||||
}
|
||||
27
testing/regression/syntax/conditional-logical-or.ink
Normal file
27
testing/regression/syntax/conditional-logical-or.ink
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:23, line:27>
|
||||
// CHECK-NEXT: |--TempDecl <line:23, col:3:13>
|
||||
// CHECK-NEXT: | |--Identifier `x` <col:8, col:9>
|
||||
// CHECK-NEXT: | `--NumberLiteral `2` <col:12, col:13>
|
||||
// CHECK-NEXT: `--ContentStmt <line:25, col:1:56>
|
||||
// CHECK-NEXT: `--Content <col:1, col:56>
|
||||
// CHECK-NEXT: `--IfStmt <line:25, line:27>
|
||||
// CHECK-NEXT: |--LogicalOrExpr <col:2, col:22>
|
||||
// CHECK-NEXT: | |--LogicalGreaterThanOrEqualExpr <col:2, col:8>
|
||||
// CHECK-NEXT: | | |--Identifier `x` <col:2, col:3>
|
||||
// CHECK-NEXT: | | `--NumberLiteral `1` <col:7, col:8>
|
||||
// CHECK-NEXT: | `--LogicalEqualityExpr <col:12, col:22>
|
||||
// CHECK-NEXT: | |--Identifier `x` <col:12, col:13>
|
||||
// CHECK-NEXT: | `--FalseLiteral <col:17, col:22>
|
||||
// CHECK-NEXT: `--BlockStmt <line:26, line:26>
|
||||
// CHECK-NEXT: `--ContentStmt <line:26, col:5:31>
|
||||
// CHECK-NEXT: `--Content <col:5, col:31>
|
||||
// CHECK-NEXT: `--StringLiteral `Greater than one or false!` <col:5, col:31>
|
||||
|
||||
~ temp x = 2
|
||||
|
||||
{x >= 1 or x == false:
|
||||
Greater than one or false!
|
||||
}
|
||||
23
testing/regression/syntax/conditional-simple-if-else.ink
Normal file
23
testing/regression/syntax/conditional-simple-if-else.ink
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:19, line:23>
|
||||
// CHECK-NEXT: `--ContentStmt <line:19, col:1:52>
|
||||
// CHECK-NEXT: `--Content <col:1, col:52>
|
||||
// CHECK-NEXT: `--IfStmt <line:19, line:23>
|
||||
// CHECK-NEXT: |--TrueLiteral <col:2, col:6>
|
||||
// CHECK-NEXT: |--BlockStmt <line:20, line:20>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:20, col:5:18>
|
||||
// CHECK-NEXT: | `--Content <col:5, col:18>
|
||||
// CHECK-NEXT: | `--StringLiteral `Hello, world!` <col:5, col:18>
|
||||
// CHECK-NEXT: `--ElseBranch <col:3, col:13>
|
||||
// CHECK-NEXT: `--BlockStmt <line:22, line:22>
|
||||
// CHECK-NEXT: `--ContentStmt <line:22, col:5:17>
|
||||
// CHECK-NEXT: `--Content <col:5, col:17>
|
||||
// CHECK-NEXT: `--StringLiteral `Unreachable!` <col:5, col:17>
|
||||
|
||||
{true:
|
||||
Hello, world!
|
||||
- else:
|
||||
Unreachable!
|
||||
}
|
||||
16
testing/regression/syntax/conditional-simple-if.ink
Normal file
16
testing/regression/syntax/conditional-simple-if.ink
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:14, line:16>
|
||||
// CHECK-NEXT: `--ContentStmt <line:14, col:1:27>
|
||||
// CHECK-NEXT: `--Content <col:1, col:27>
|
||||
// CHECK-NEXT: `--IfStmt <line:14, line:16>
|
||||
// CHECK-NEXT: |--TrueLiteral <col:2, col:6>
|
||||
// CHECK-NEXT: `--BlockStmt <line:15, line:15>
|
||||
// CHECK-NEXT: `--ContentStmt <line:15, col:5:18>
|
||||
// CHECK-NEXT: `--Content <col:5, col:18>
|
||||
// CHECK-NEXT: `--StringLiteral `Hello, world!` <col:5, col:18>
|
||||
|
||||
{true:
|
||||
Hello, world!
|
||||
}
|
||||
43
testing/regression/syntax/conditional-simple-switch.ink
Normal file
43
testing/regression/syntax/conditional-simple-switch.ink
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:36, line:43>
|
||||
// CHECK-NEXT: |--TempDecl <line:36, col:3:13>
|
||||
// CHECK-NEXT: | |--Identifier `x` <col:8, col:9>
|
||||
// CHECK-NEXT: | `--NumberLiteral `3` <col:12, col:13>
|
||||
// CHECK-NEXT: `--ContentStmt <line:38, col:1:51>
|
||||
// CHECK-NEXT: `--Content <col:1, col:51>
|
||||
// CHECK-NEXT: `--SwitchStmt <line:38, line:43>
|
||||
// CHECK-NEXT: |--Identifier `x` <col:3, col:4>
|
||||
// CHECK-NEXT: |--SwitchCase <col:3, col:7>
|
||||
// CHECK-NEXT: | |--NumberLiteral `0` <col:3, col:4>
|
||||
// CHECK-NEXT: | `--BlockStmt <line:39, line:39>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:39, col:7:11>
|
||||
// CHECK-NEXT: | `--Content <col:7, col:11>
|
||||
// CHECK-NEXT: | `--StringLiteral `zero` <col:7, col:11>
|
||||
// CHECK-NEXT: |--SwitchCase <col:3, col:7>
|
||||
// CHECK-NEXT: | |--NumberLiteral `1` <col:3, col:4>
|
||||
// CHECK-NEXT: | `--BlockStmt <line:40, line:40>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:40, col:7:10>
|
||||
// CHECK-NEXT: | `--Content <col:7, col:10>
|
||||
// CHECK-NEXT: | `--StringLiteral `one` <col:7, col:10>
|
||||
// CHECK-NEXT: |--SwitchCase <col:3, col:7>
|
||||
// CHECK-NEXT: | |--NumberLiteral `2` <col:3, col:4>
|
||||
// CHECK-NEXT: | `--BlockStmt <line:41, line:41>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:41, col:7:10>
|
||||
// CHECK-NEXT: | `--Content <col:7, col:10>
|
||||
// CHECK-NEXT: | `--StringLiteral `two` <col:7, col:10>
|
||||
// CHECK-NEXT: `--ElseBranch <col:3, col:9>
|
||||
// CHECK-NEXT: `--BlockStmt <line:42, line:42>
|
||||
// CHECK-NEXT: `--ContentStmt <line:42, col:9:13>
|
||||
// CHECK-NEXT: `--Content <col:9, col:13>
|
||||
// CHECK-NEXT: `--StringLiteral `lots` <col:9, col:13>
|
||||
|
||||
~ temp x = 3
|
||||
|
||||
{ x:
|
||||
- 0: zero
|
||||
- 1: one
|
||||
- 2: two
|
||||
- else: lots
|
||||
}
|
||||
1
testing/regression/syntax/conditional-substitution.ink
Normal file
1
testing/regression/syntax/conditional-substitution.ink
Normal file
|
|
@ -0,0 +1 @@
|
|||
{true: Hello world!}
|
||||
1
testing/regression/syntax/const-expected-expression.ink
Normal file
1
testing/regression/syntax/const-expected-expression.ink
Normal file
|
|
@ -0,0 +1 @@
|
|||
CONST foo =
|
||||
23
testing/regression/syntax/content-substitution.ink
Normal file
23
testing/regression/syntax/content-substitution.ink
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:21, line:23>
|
||||
// CHECK-NEXT: |--VarDecl <line:21, col:1:24>
|
||||
// CHECK-NEXT: | |--Identifier `x` <col:5, col:6>
|
||||
// CHECK-NEXT: | `--StringExpr `"Hello world 1"` <col:9, col:24>
|
||||
// CHECK-NEXT: | `--StringLiteral `Hello world 1` <col:10, col:23>
|
||||
// CHECK-NEXT: |--ContentStmt <line:22, col:1:4>
|
||||
// CHECK-NEXT: | `--Content <col:1, col:4>
|
||||
// CHECK-NEXT: | `--InlineLogicExpr <col:1, col:4>
|
||||
// CHECK-NEXT: | `--Identifier `x` <col:2, col:3>
|
||||
// CHECK-NEXT: `--ContentStmt <line:23, col:1:19>
|
||||
// CHECK-NEXT: `--Content <col:1, col:19>
|
||||
// CHECK-NEXT: |--StringLiteral `Hello ` <col:1, col:7>
|
||||
// CHECK-NEXT: |--InlineLogicExpr <col:7, col:16>
|
||||
// CHECK-NEXT: | `--StringExpr `"world"` <col:8, col:15>
|
||||
// CHECK-NEXT: | `--StringLiteral `world` <col:9, col:14>
|
||||
// CHECK-NEXT: `--StringLiteral ` 2.` <col:16, col:19>
|
||||
|
||||
VAR x = "Hello world 1"
|
||||
{x}
|
||||
Hello {"world"} 2.
|
||||
9
testing/regression/syntax/empty-choice-branch.ink
Normal file
9
testing/regression/syntax/empty-choice-branch.ink
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:9, line:9>
|
||||
// CHECK-NEXT: `--ChoiceStmt <line:9, line:9>
|
||||
// CHECK-NEXT: `--ChoiceStarStmt <line:9, col:1:2>
|
||||
// CHECK-NEXT: `--ChoiceContentExpr <col:2, col:2>
|
||||
|
||||
*
|
||||
3
testing/regression/syntax/empty-file.ink
Normal file
3
testing/regression/syntax/empty-file.ink
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
12
testing/regression/syntax/empty-knots.ink
Normal file
12
testing/regression/syntax/empty-knots.ink
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: |--KnotDecl <line:11, line:11>
|
||||
// CHECK-NEXT: | `--KnotProto <col:1, col:5>
|
||||
// CHECK-NEXT: | `--Identifier `a` <col:4, col:5>
|
||||
// CHECK-NEXT: `--KnotDecl <line:12, line:12>
|
||||
// CHECK-NEXT: `--KnotProto <col:1, col:5>
|
||||
// CHECK-NEXT: `--Identifier `b` <col:4, col:5>
|
||||
|
||||
== a
|
||||
== b
|
||||
1
testing/regression/syntax/empty-logic.ink
Normal file
1
testing/regression/syntax/empty-logic.ink
Normal file
|
|
@ -0,0 +1 @@
|
|||
~
|
||||
16
testing/regression/syntax/expression-statement.ink
Normal file
16
testing/regression/syntax/expression-statement.ink
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:16, line:16>
|
||||
// CHECK-NEXT: `--ExprStmt <line:16, col:3:20>
|
||||
// CHECK-NEXT: `--SubtractExpr <col:4, col:20>
|
||||
// CHECK-NEXT: |--MultiplyExpr <col:4, col:15>
|
||||
// CHECK-NEXT: | |--AddExpr <col:4, col:10>
|
||||
// CHECK-NEXT: | | |--NegateExpr <col:4, col:6>
|
||||
// CHECK-NEXT: | | | `--NumberLiteral `1` <col:5, col:6>
|
||||
// CHECK-NEXT: | | `--NumberLiteral `2` <col:9, col:10>
|
||||
// CHECK-NEXT: | `--NumberLiteral `3` <col:14, col:15>
|
||||
// CHECK-NEXT: `--NegateExpr <col:18, col:20>
|
||||
// CHECK-NEXT: `--NumberLiteral `4` <col:19, col:20>
|
||||
|
||||
~ (-1 + 2) * 3 - -4
|
||||
46
testing/regression/syntax/factorial.ink
Normal file
46
testing/regression/syntax/factorial.ink
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: |--BlockStmt <line:39, line:39>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:39, col:1:18>
|
||||
// CHECK-NEXT: | `--Content <col:1, col:18>
|
||||
// CHECK-NEXT: | `--InlineLogicExpr <col:1, col:18>
|
||||
// CHECK-NEXT: | `--CallExpr <col:3, col:17>
|
||||
// CHECK-NEXT: | |--Identifier `factorial` <col:3, col:12>
|
||||
// CHECK-NEXT: | `--ArgumentList <col:12, col:17>
|
||||
// CHECK-NEXT: | `--NumberLiteral `10` <col:13, col:15>
|
||||
// CHECK-NEXT: `--FunctionDecl <line:41, line:46>
|
||||
// CHECK-NEXT: |--FunctionProto <col:1, col:25>
|
||||
// CHECK-NEXT: | |--Identifier `factorial` <col:13, col:22>
|
||||
// CHECK-NEXT: | `--ParamList <col:22, col:25>
|
||||
// CHECK-NEXT: | `--ParamDecl `n` <col:23, col:24>
|
||||
// CHECK-NEXT: `--BlockStmt <line:42, line:46>
|
||||
// CHECK-NEXT: `--ContentStmt <line:42, col:3:83>
|
||||
// CHECK-NEXT: `--Content <col:3, col:83>
|
||||
// CHECK-NEXT: `--IfStmt <line:42, line:46>
|
||||
// CHECK-NEXT: |--LogicalEqualityExpr <col:5, col:11>
|
||||
// CHECK-NEXT: | |--Identifier `n` <col:5, col:6>
|
||||
// CHECK-NEXT: | `--NumberLiteral `1` <col:10, col:11>
|
||||
// CHECK-NEXT: |--BlockStmt <line:43, line:43>
|
||||
// CHECK-NEXT: | `--ReturnStmt <line:43, col:9:17>
|
||||
// CHECK-NEXT: | `--NumberLiteral `1` <col:16, col:17>
|
||||
// CHECK-NEXT: `--ElseBranch <col:7, col:19>
|
||||
// CHECK-NEXT: `--BlockStmt <line:45, line:45>
|
||||
// CHECK-NEXT: `--ReturnStmt <line:45, col:9:38>
|
||||
// CHECK-NEXT: `--MultiplyExpr <col:17, col:37>
|
||||
// CHECK-NEXT: |--Identifier `n` <col:17, col:18>
|
||||
// CHECK-NEXT: `--CallExpr <col:21, col:37>
|
||||
// CHECK-NEXT: |--Identifier `factorial` <col:21, col:30>
|
||||
// CHECK-NEXT: `--ArgumentList <col:30, col:37>
|
||||
// CHECK-NEXT: `--SubtractExpr <col:31, col:36>
|
||||
// CHECK-NEXT: |--Identifier `n` <col:31, col:32>
|
||||
// CHECK-NEXT: `--NumberLiteral `1` <col:35, col:36>
|
||||
|
||||
{ factorial(10) }
|
||||
|
||||
== function factorial(n)
|
||||
{ n == 1:
|
||||
~ return 1
|
||||
- else:
|
||||
~ return (n * factorial(n - 1))
|
||||
}
|
||||
62
testing/regression/syntax/fibonacci.ink
Normal file
62
testing/regression/syntax/fibonacci.ink
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: |--BlockStmt <line:52, line:52>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:52, col:1:12>
|
||||
// CHECK-NEXT: | `--Content <col:1, col:12>
|
||||
// CHECK-NEXT: | `--InlineLogicExpr <col:1, col:12>
|
||||
// CHECK-NEXT: | `--CallExpr <col:3, col:11>
|
||||
// CHECK-NEXT: | |--Identifier `fib` <col:3, col:6>
|
||||
// CHECK-NEXT: | `--ArgumentList <col:6, col:11>
|
||||
// CHECK-NEXT: | `--NumberLiteral `10` <col:7, col:9>
|
||||
// CHECK-NEXT: `--FunctionDecl <line:54, line:62>
|
||||
// CHECK-NEXT: |--FunctionProto <col:1, col:19>
|
||||
// CHECK-NEXT: | |--Identifier `fib` <col:13, col:16>
|
||||
// CHECK-NEXT: | `--ParamList <col:16, col:19>
|
||||
// CHECK-NEXT: | `--ParamDecl `n` <col:17, col:18>
|
||||
// CHECK-NEXT: `--BlockStmt <line:55, line:62>
|
||||
// CHECK-NEXT: `--ContentStmt <line:55, col:3:121>
|
||||
// CHECK-NEXT: `--Content <col:3, col:121>
|
||||
// CHECK-NEXT: `--MultiIfStmt <line:55, line:62>
|
||||
// CHECK-NEXT: |--IfBranch <col:7, col:21>
|
||||
// CHECK-NEXT: | |--LogicalEqualityExpr <col:7, col:13>
|
||||
// CHECK-NEXT: | | |--Identifier `n` <col:7, col:8>
|
||||
// CHECK-NEXT: | | `--NumberLiteral `0` <col:12, col:13>
|
||||
// CHECK-NEXT: | `--BlockStmt <line:57, line:57>
|
||||
// CHECK-NEXT: | `--ReturnStmt <line:57, col:9:17>
|
||||
// CHECK-NEXT: | `--NumberLiteral `0` <col:16, col:17>
|
||||
// CHECK-NEXT: |--IfBranch <col:7, col:21>
|
||||
// CHECK-NEXT: | |--LogicalEqualityExpr <col:7, col:13>
|
||||
// CHECK-NEXT: | | |--Identifier `n` <col:7, col:8>
|
||||
// CHECK-NEXT: | | `--NumberLiteral `1` <col:12, col:13>
|
||||
// CHECK-NEXT: | `--BlockStmt <line:59, line:59>
|
||||
// CHECK-NEXT: | `--ReturnStmt <line:59, col:9:17>
|
||||
// CHECK-NEXT: | `--NumberLiteral `1` <col:16, col:17>
|
||||
// CHECK-NEXT: `--ElseBranch <col:7, col:19>
|
||||
// CHECK-NEXT: `--BlockStmt <line:61, line:61>
|
||||
// CHECK-NEXT: `--ReturnStmt <line:61, col:9:39>
|
||||
// CHECK-NEXT: `--AddExpr <col:16, col:39>
|
||||
// CHECK-NEXT: |--CallExpr <col:16, col:27>
|
||||
// CHECK-NEXT: | |--Identifier `fib` <col:16, col:19>
|
||||
// CHECK-NEXT: | `--ArgumentList <col:19, col:27>
|
||||
// CHECK-NEXT: | `--SubtractExpr <col:20, col:25>
|
||||
// CHECK-NEXT: | |--Identifier `n` <col:20, col:21>
|
||||
// CHECK-NEXT: | `--NumberLiteral `1` <col:24, col:25>
|
||||
// CHECK-NEXT: `--CallExpr <col:29, col:39>
|
||||
// CHECK-NEXT: |--Identifier `fib` <col:29, col:32>
|
||||
// CHECK-NEXT: `--ArgumentList <col:32, col:39>
|
||||
// CHECK-NEXT: `--SubtractExpr <col:33, col:38>
|
||||
// CHECK-NEXT: |--Identifier `n` <col:33, col:34>
|
||||
// CHECK-NEXT: `--NumberLiteral `2` <col:37, col:38>
|
||||
|
||||
{ fib(10) }
|
||||
|
||||
== function fib(n)
|
||||
{
|
||||
- n == 0:
|
||||
~ return 0
|
||||
- n == 1:
|
||||
~ return 1
|
||||
- else:
|
||||
~ return fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
28
testing/regression/syntax/function-simple.ink
Normal file
28
testing/regression/syntax/function-simple.ink
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: |--BlockStmt <line:25, line:25>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:25, col:1:13>
|
||||
// CHECK-NEXT: | `--Content <col:1, col:13>
|
||||
// CHECK-NEXT: | `--InlineLogicExpr <col:1, col:13>
|
||||
// CHECK-NEXT: | `--CallExpr <col:2, col:12>
|
||||
// CHECK-NEXT: | |--Identifier `func` <col:2, col:6>
|
||||
// CHECK-NEXT: | `--ArgumentList <col:6, col:12>
|
||||
// CHECK-NEXT: | |--NumberLiteral `1` <col:7, col:8>
|
||||
// CHECK-NEXT: | `--NumberLiteral `2` <col:10, col:11>
|
||||
// CHECK-NEXT: `--FunctionDecl <line:27, line:28>
|
||||
// CHECK-NEXT: |--FunctionProto <col:1, col:23>
|
||||
// CHECK-NEXT: | |--Identifier `func` <col:13, col:17>
|
||||
// CHECK-NEXT: | `--ParamList <col:17, col:23>
|
||||
// CHECK-NEXT: | |--ParamDecl `a` <col:18, col:19>
|
||||
// CHECK-NEXT: | `--ParamDecl `b` <col:21, col:22>
|
||||
// CHECK-NEXT: `--BlockStmt <line:28, line:28>
|
||||
// CHECK-NEXT: `--ReturnStmt <line:28, col:3:15>
|
||||
// CHECK-NEXT: `--AddExpr <col:10, col:15>
|
||||
// CHECK-NEXT: |--Identifier `a` <col:10, col:11>
|
||||
// CHECK-NEXT: `--Identifier `b` <col:14, col:15>
|
||||
|
||||
{func(1, 2)}
|
||||
|
||||
== function func(a, b)
|
||||
~ return a + b
|
||||
9
testing/regression/syntax/hello-world.ink
Normal file
9
testing/regression/syntax/hello-world.ink
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:9, line:9>
|
||||
// CHECK-NEXT: `--ContentStmt <line:9, col:1:14>
|
||||
// CHECK-NEXT: `--Content <col:1, col:14>
|
||||
// CHECK-NEXT: `--StringLiteral `Hello, world!` <col:1, col:14>
|
||||
|
||||
Hello, world!
|
||||
2
testing/regression/syntax/knot-expected-identifier.ink
Normal file
2
testing/regression/syntax/knot-expected-identifier.ink
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
===
|
||||
Hello, world!
|
||||
34
testing/regression/syntax/knot-qualified-lookup.ink
Normal file
34
testing/regression/syntax/knot-qualified-lookup.ink
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: |--BlockStmt <line:30, line:30>
|
||||
// CHECK-NEXT: | `--DivertStmt <line:30, col:1:16>
|
||||
// CHECK-NEXT: | `--Divert <col:1, col:16>
|
||||
// CHECK-NEXT: | `--CallExpr <col:4, col:16>
|
||||
// CHECK-NEXT: | |--SelectorExpr <col:4, col:7>
|
||||
// CHECK-NEXT: | | |--Identifier `a` <col:4, col:5>
|
||||
// CHECK-NEXT: | | `--Identifier `b` <col:6, col:7>
|
||||
// CHECK-NEXT: | `--ArgumentList <col:7, col:16>
|
||||
// CHECK-NEXT: | `--StringExpr `"Brett"` <col:8, col:15>
|
||||
// CHECK-NEXT: | `--StringLiteral `Brett` <col:9, col:14>
|
||||
// CHECK-NEXT: `--KnotDecl <line:32, line:34>
|
||||
// CHECK-NEXT: |--KnotProto <col:1, col:5>
|
||||
// CHECK-NEXT: | `--Identifier `a` <col:4, col:5>
|
||||
// CHECK-NEXT: `--StitchDecl <line:33, line:34>
|
||||
// CHECK-NEXT: |--StitchProto <col:1, col:10>
|
||||
// CHECK-NEXT: | |--Identifier `b` <col:3, col:4>
|
||||
// CHECK-NEXT: | `--ParamList <col:4, col:10>
|
||||
// CHECK-NEXT: | `--ParamDecl `name` <col:5, col:9>
|
||||
// CHECK-NEXT: `--BlockStmt <line:34, line:34>
|
||||
// CHECK-NEXT: `--ContentStmt <line:34, col:1:15>
|
||||
// CHECK-NEXT: `--Content <col:1, col:15>
|
||||
// CHECK-NEXT: |--StringLiteral `Hello, ` <col:1, col:8>
|
||||
// CHECK-NEXT: |--InlineLogicExpr <col:8, col:14>
|
||||
// CHECK-NEXT: | `--Identifier `name` <col:9, col:13>
|
||||
// CHECK-NEXT: `--StringLiteral `!` <col:14, col:15>
|
||||
|
||||
-> a.b("Brett")
|
||||
|
||||
== a
|
||||
= b(name)
|
||||
Hello, {name}!
|
||||
31
testing/regression/syntax/knot-stitches.ink
Normal file
31
testing/regression/syntax/knot-stitches.ink
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--KnotDecl <line:26, line:31>
|
||||
// CHECK-NEXT: |--KnotProto <col:1, col:13>
|
||||
// CHECK-NEXT: | `--Identifier `knot` <col:5, col:9>
|
||||
// CHECK-NEXT: |--BlockStmt <line:27, line:27>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:27, col:1:19>
|
||||
// CHECK-NEXT: | `--Content <col:1, col:19>
|
||||
// CHECK-NEXT: | `--StringLiteral `Hello from `knot`!` <col:1, col:19>
|
||||
// CHECK-NEXT: |--StitchDecl <line:28, line:29>
|
||||
// CHECK-NEXT: | |--StitchProto <col:1, col:4>
|
||||
// CHECK-NEXT: | | `--Identifier `a` <col:3, col:4>
|
||||
// CHECK-NEXT: | `--BlockStmt <line:29, line:29>
|
||||
// CHECK-NEXT: | `--ContentStmt <line:29, col:1:21>
|
||||
// CHECK-NEXT: | `--Content <col:1, col:21>
|
||||
// CHECK-NEXT: | `--StringLiteral `Hello from `knot.a`!` <col:1, col:21>
|
||||
// CHECK-NEXT: `--StitchDecl <line:30, line:31>
|
||||
// CHECK-NEXT: |--StitchProto <col:1, col:4>
|
||||
// CHECK-NEXT: | `--Identifier `b` <col:3, col:4>
|
||||
// CHECK-NEXT: `--BlockStmt <line:31, line:31>
|
||||
// CHECK-NEXT: `--ContentStmt <line:31, col:1:21>
|
||||
// CHECK-NEXT: `--Content <col:1, col:21>
|
||||
// CHECK-NEXT: `--StringLiteral `Hello from `knot.b`!` <col:1, col:21>
|
||||
|
||||
=== knot ===
|
||||
Hello from `knot`!
|
||||
= a
|
||||
Hello from `knot.a`!
|
||||
= b
|
||||
Hello from `knot.b`!
|
||||
17
testing/regression/syntax/nested-stitch.ink
Normal file
17
testing/regression/syntax/nested-stitch.ink
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--KnotDecl <line:15, line:17>
|
||||
// CHECK-NEXT: |--KnotProto <col:1, col:13>
|
||||
// CHECK-NEXT: | `--Identifier `knot` <col:5, col:9>
|
||||
// CHECK-NEXT: `--StitchDecl <line:16, line:17>
|
||||
// CHECK-NEXT: |--StitchProto <col:1, col:9>
|
||||
// CHECK-NEXT: | `--Identifier `stitch` <col:3, col:9>
|
||||
// CHECK-NEXT: `--BlockStmt <line:17, line:17>
|
||||
// CHECK-NEXT: `--ContentStmt <line:17, col:1:14>
|
||||
// CHECK-NEXT: `--Content <col:1, col:14>
|
||||
// CHECK-NEXT: `--StringLiteral `Hello, world!` <col:1, col:14>
|
||||
|
||||
=== knot ===
|
||||
= stitch
|
||||
Hello, world!
|
||||
13
testing/regression/syntax/simple-assignment.ink
Normal file
13
testing/regression/syntax/simple-assignment.ink
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:12, line:13>
|
||||
// CHECK-NEXT: |--TempDecl <line:12, col:3:15>
|
||||
// CHECK-NEXT: | |--Identifier `a` <col:8, col:9>
|
||||
// CHECK-NEXT: | `--NumberLiteral `123` <col:12, col:15>
|
||||
// CHECK-NEXT: `--AssignStmt <line:13, col:3:10>
|
||||
// CHECK-NEXT: |--Identifier `a` <col:3, col:4>
|
||||
// CHECK-NEXT: `--NumberLiteral `321` <col:7, col:10>
|
||||
|
||||
~ temp a = 123
|
||||
~ a = 321
|
||||
18
testing/regression/syntax/simple-choice.ink
Normal file
18
testing/regression/syntax/simple-choice.ink
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--BlockStmt <line:16, line:18>
|
||||
// CHECK-NEXT: `--ChoiceStmt <line:16, line:18>
|
||||
// CHECK-NEXT: |--ChoiceStarStmt <line:16, col:1:4>
|
||||
// CHECK-NEXT: | `--ChoiceContentExpr <col:3, col:4>
|
||||
// CHECK-NEXT: | `--ChoiceStartContentExpr `A` <col:3, col:4>
|
||||
// CHECK-NEXT: |--ChoiceStarStmt <line:17, col:1:4>
|
||||
// CHECK-NEXT: | `--ChoiceContentExpr <col:3, col:4>
|
||||
// CHECK-NEXT: | `--ChoiceStartContentExpr `B` <col:3, col:4>
|
||||
// CHECK-NEXT: `--ChoiceStarStmt <line:18, col:1:4>
|
||||
// CHECK-NEXT: `--ChoiceContentExpr <col:3, col:4>
|
||||
// CHECK-NEXT: `--ChoiceStartContentExpr `C` <col:3, col:4>
|
||||
|
||||
* A
|
||||
* B
|
||||
* C
|
||||
13
testing/regression/syntax/simple-knot.ink
Normal file
13
testing/regression/syntax/simple-knot.ink
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--KnotDecl <line:12, line:13>
|
||||
// CHECK-NEXT: |--KnotProto <col:1, col:13>
|
||||
// CHECK-NEXT: | `--Identifier `knot` <col:5, col:9>
|
||||
// CHECK-NEXT: `--BlockStmt <line:13, line:13>
|
||||
// CHECK-NEXT: `--ContentStmt <line:13, col:1:14>
|
||||
// CHECK-NEXT: `--Content <col:1, col:14>
|
||||
// CHECK-NEXT: `--StringLiteral `Hello, world!` <col:1, col:14>
|
||||
|
||||
=== knot ===
|
||||
Hello, world!
|
||||
13
testing/regression/syntax/simple-stitch.ink
Normal file
13
testing/regression/syntax/simple-stitch.ink
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
|
||||
|
||||
// CHECK: File "<STDIN>"
|
||||
// CHECK-NEXT: `--StitchDecl <line:12, line:13>
|
||||
// CHECK-NEXT: |--StitchProto <col:1, col:9>
|
||||
// CHECK-NEXT: | `--Identifier `stitch` <col:3, col:9>
|
||||
// CHECK-NEXT: `--BlockStmt <line:13, line:13>
|
||||
// CHECK-NEXT: `--ContentStmt <line:13, col:1:14>
|
||||
// CHECK-NEXT: `--Content <col:1, col:14>
|
||||
// CHECK-NEXT: `--StringLiteral `Hello, world!` <col:1, col:14>
|
||||
|
||||
= stitch
|
||||
Hello, world!
|
||||
1
testing/regression/syntax/var-expected-expression.ink
Normal file
1
testing/regression/syntax/var-expected-expression.ink
Normal file
|
|
@ -0,0 +1 @@
|
|||
VAR foo =
|
||||
Loading…
Add table
Add a link
Reference in a new issue