Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@ pub fn build(b: *Build) !void {
.root_module = exe_mod,
});
b.installArtifact(exe);
const run = b.addRunArtifact(exe);
run.addArgs(&.{
"lola",
"run",
"hello.lola",
"--mode",
"source",
});

const benchmark_renderer_mod = b.createModule(.{
.root_source_file = b.path("src/benchmark/render.zig"),
Expand Down Expand Up @@ -247,6 +239,9 @@ pub fn build(b: *Build) !void {
}

const run_cmd = b.addRunArtifact(exe);
if (b.args) |args| {
run_cmd.addArgs(args);
}
run_cmd.step.dependOn(b.getInstallStep());

const run_step = b.step("run", "Run the app");
Expand Down
6 changes: 6 additions & 0 deletions src/library/common/ir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pub const InstructionName = enum(u8) {
push_true = 41,
push_false = 42,
push_void = 43,
struct_pack = 44,
struct_store = 45,
struct_load = 46,
};

/// This union contains each possible instruction with its (optional) arguments already encoded.
Expand Down Expand Up @@ -106,4 +109,7 @@ pub const Instruction = union(InstructionName) {
push_true: NoArg,
push_false: NoArg,
push_void: NoArg,
struct_pack: SingleArg(u16),
struct_store: NoArg,
struct_load: NoArg,
};
20 changes: 19 additions & 1 deletion src/library/compiler/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ fn expressionTypeToString(src: ast.Expression.Type) []const u8 {
.string_literal => "string literal",
.unary_operator => "unary operator application",
.binary_operator => "binary operator application",
.field_access => "field access",
.struct_literal => "struct literal",
};
}

Expand Down Expand Up @@ -74,6 +76,17 @@ fn validateExpression(state: *AnalysisState, diagnostics: *Diagnostics, scope: *
}
},

.field_access => |_| {
return TypeSet.any;
},

.struct_literal => |lit| {
for (lit) |entry| {
_ = try validateExpression(state, diagnostics, scope, entry.@"1".*);
}
return TypeSet.from(.@"struct");
},

.variable_expr => |variable_name| {

// Check reserved names
Expand Down Expand Up @@ -230,6 +243,12 @@ fn validateStore(state: *AnalysisState, diagnostics: *Diagnostics, scope: *Scope
}
},

.field_access => |field_access| {
const struct_val = try validateExpression(state, diagnostics, scope, field_access.@"struct".*);
try performTypeCheck(diagnostics, field_access.@"struct".location, .from(.@"struct"), struct_val);
try validateStore(state, diagnostics, scope, field_access.@"struct".*, struct_val);
},

else => unreachable,
}
}
Expand Down Expand Up @@ -477,4 +496,3 @@ test "detect doubly-declared global variables" {
"Global variable a is already declared!",
});
}

7 changes: 6 additions & 1 deletion src/library/compiler/ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub const Expression = struct {
/// Cs `lvalue`.
pub fn isAssignable(self: Self) bool {
return switch (self.type) {
.array_indexer, .variable_expr => true,
.array_indexer, .variable_expr, .field_access => true,
else => false,
};
}
Expand All @@ -51,6 +51,7 @@ pub const Expression = struct {
},
variable_expr: []const u8,
array_literal: []Expression,
struct_literal: []struct { []const u8, *Expression },
function_call: struct {
// this must be a expression of type `variable_expr`
function: *Expression,
Expand All @@ -72,6 +73,10 @@ pub const Expression = struct {
lhs: *Expression,
rhs: *Expression,
},
field_access: struct {
@"struct": *Expression,
name: []const u8,
},
};
};

Expand Down
26 changes: 26 additions & 0 deletions src/library/compiler/codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ fn emitStore(debug_symbols: *DebugSyms, scope: *Scope, writer: *CodeWriter, expr
try emitStore(debug_symbols, scope, writer, indexer.value.*); // now store back the value on the stack
},

.field_access => |field_access| {
try writer.emitInstruction(.{ .push_str = .{ .value = field_access.name } });
try emitExpression(debug_symbols, scope, writer, field_access.@"struct".*);
try writer.emitInstruction(.struct_store);
try emitStore(debug_symbols, scope, writer, field_access.@"struct".*);
},

.variable_expr => |variable_name| {
if (std.mem.eql(u8, variable_name, "true")) {
return error.InvalidStoreTarget;
Expand Down Expand Up @@ -119,6 +126,25 @@ fn emitExpression(debug_symbols: *DebugSyms, scope: *Scope, writer: *CodeWriter,
});
},

.field_access => |field_access| {
// field_access.
try writer.emitInstruction(.{ .push_str = .{ .value = field_access.name } });
try emitExpression(debug_symbols, scope, writer, field_access.@"struct".*);
try writer.emitInstruction(.struct_load);
},

.struct_literal => |s| {
var i: usize = s.len;
while (i > 0) {
i -= 1;
try writer.emitInstruction(.{ .push_str = .{ .value = s[i].@"0" } });
try emitExpression(debug_symbols, scope, writer, s[i].@"1".*);
}
try writer.emitInstruction(Instruction{
.struct_pack = .{ .value = @as(u16, @intCast(s.len)) },
});
},

.function_call => |call| {
var i: usize = call.arguments.len;
while (i > 0) {
Expand Down
127 changes: 96 additions & 31 deletions src/library/compiler/parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -657,40 +657,53 @@ pub fn parse(
};
},

// method call
//field access or method call
.@"." => blk: {
const method_name = try self.accept(is(.identifier));

_ = try self.accept(is(.@"("));

var args = std.ArrayList(ast.Expression).empty;
defer args.deinit(self.allocator);

var loc = value.location;

if (self.accept(is(.@")"))) |_| {
// this is the end of the argument list
} else |_| {
while (true) {
const arg = try self.acceptExpression();
try args.append(self.allocator, arg);
const terminator = try self.accept(oneOf(.{ .@")", .@"," }));
loc = terminator.location.merge(loc);
if (terminator.type == .@")")
break;
const field_name = try self.accept(is(.identifier));

if (self.accept(is(.@"("))) |_| {
// method call

var args = std.ArrayList(ast.Expression).empty;
defer args.deinit(self.allocator);

var loc = value.location;

if (self.accept(is(.@")"))) |_| {
// this is the end of the argument list
} else |_| {
while (true) {
const arg = try self.acceptExpression();
try args.append(self.allocator, arg);
const terminator = try self.accept(oneOf(.{ .@")", .@"," }));
loc = terminator.location.merge(loc);
if (terminator.type == .@")")
break;
}
}
}

break :blk ast.Expression{
.location = loc,
.type = .{
.method_call = .{
.object = try self.moveToHeap(value),
.name = method_name.text,
.arguments = try args.toOwnedSlice(self.allocator),
break :blk ast.Expression{
.location = loc,
.type = .{
.method_call = .{
.object = try self.moveToHeap(value),
.name = field_name.text,
.arguments = try args.toOwnedSlice(self.allocator),
},
},
},
};
};
} else |_| {
//field access
break :blk ast.Expression{
.location = value.location,
.type = .{
.field_access = .{
.@"struct" = try self.moveToHeap(value),
.name = field_name.text,
},
},
};
}
},

else => unreachable,
Expand All @@ -701,10 +714,63 @@ pub fn parse(
return value;
}

fn acceptStructExpression(self: *Self) ParseError!ast.Expression {
const state = self.saveState();
errdefer self.restoreState(state);

const token = try self.accept(is(.@"["));
var loc: Location = token.location;

var entries: std.ArrayList(struct { []const u8, *ast.Expression }) = .empty;
errdefer {
for (entries.items) |entry| {
self.allocator.destroy(entry.@"1");
}
entries.deinit(self.allocator);
}
while (true) {
if (self.accept(is(.@"]"))) |_| {
break;
} else |_| {
_ = try self.accept(is(.@"."));
const field = try self.accept(is(.identifier));
_ = try self.accept(is(.@"="));
const item = try self.acceptExpression();
try entries.append(self.allocator, .{ field.text, try self.moveToHeap(item) });

const delimit = try self.accept(oneOf(.{ .@",", .@"]" }));
loc = loc.merge(delimit.location);
if (delimit.type == .@"]")
break;
}
}
if (entries.items.len == 0) {
//this is a list type by default
entries.deinit(self.allocator);
return ast.Expression{
.location = loc,
.type = .{ .array_literal = try self.allocator.alloc(ast.Expression, 0) },
};
}

return ast.Expression{
.location = loc,
.type = .{
.struct_literal = try entries.toOwnedSlice(self.allocator),
},
};
}

fn acceptValueExpression(self: *Self) ParseError!ast.Expression {
const state = self.saveState();
errdefer self.restoreState(state);

if (self.acceptStructExpression()) |t| {
return t;
} else |_| {
self.restoreState(state);
}

const token = try self.accept(oneOf(.{
.@"(",
.@"[",
Expand All @@ -722,7 +788,6 @@ pub fn parse(
.@"[" => {
var array = std.ArrayList(ast.Expression).empty;
defer array.deinit(self.allocator);

while (true) {
if (self.accept(is(.@"]"))) |_| {
break;
Expand Down
6 changes: 6 additions & 0 deletions src/library/compiler/typeset.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub const Type = enum {
boolean,
array,
object,
@"struct",

pub fn format(value: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
_ = fmt;
Expand All @@ -25,6 +26,7 @@ pub const TypeSet = struct {
.boolean = false,
.array = false,
.object = false,
.@"struct" = false,
};

pub const any = Self{
Expand All @@ -34,6 +36,7 @@ pub const TypeSet = struct {
.boolean = true,
.array = true,
.object = true,
.@"struct" = true,
};

void: bool,
Expand All @@ -42,6 +45,7 @@ pub const TypeSet = struct {
boolean: bool,
array: bool,
object: bool,
@"struct": bool,

pub fn from(value_type: Type) Self {
return Self{
Expand All @@ -51,6 +55,7 @@ pub const TypeSet = struct {
.boolean = (value_type == .boolean),
.array = (value_type == .array),
.object = (value_type == .object),
.@"struct" = (value_type == .@"struct"),
};
}

Expand All @@ -70,6 +75,7 @@ pub const TypeSet = struct {
.boolean => self.boolean,
.array => self.array,
.object => self.object,
.@"struct" => self.@"struct",
};
}

Expand Down
1 change: 1 addition & 0 deletions src/library/libraries/stdlib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ pub fn TypeOf(env: *const lola.runtime.Environment, context: lola.runtime.Contex
.object => "object",
.array => "array",
.enumerator => "enumerator",
.@"struct" => "struct",
});
}

Expand Down
Loading
Loading