Skip to content
Merged
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
13 changes: 13 additions & 0 deletions examples/sema/use-undeclared-var.sub
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fn main() void {
var b: i32 = "bonjour";
if b {
var a: i32 = "in if";
printf(b);
printf(a);
}
printf(a);
}

fn printf() void {

}
28 changes: 28 additions & 0 deletions increment.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.intel_syntax noprefix
.global _start

.text
_start:
push rbp
mov rbp, rsp
sub rsp, 16

mov byte ptr [rbp - 1], 'a'
mov byte ptr [rbp - 3], 5

movzx eax, byte ptr [rbp - 1]
movzx ecx, byte ptr [rbp - 3]

add eax, ecx

mov byte ptr [rbp - 1], al

mov eax, 1
mov edi, 1
lea rsi, [rbp - 1]
mov edx, 1
syscall

mov eax, 60
xor edi, edi
syscall
81 changes: 66 additions & 15 deletions src/ast.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
const std = @import("std");

const lexer_pkg = @import("lexer.zig");

const Cursor = lexer_pkg.Cursor;

const panic = std.debug.panic;
const assert = std.debug.assert;

Expand Down Expand Up @@ -51,7 +55,7 @@ pub const ProgramDecl = union(ProgramDeclTag) {
}
};

const FnDecl = struct {
pub const FnDecl = struct {
const Self = @This();

name: []const u8,
Expand Down Expand Up @@ -94,36 +98,83 @@ const ExprTag = enum {
bool_,
fn_call,
str,
var_,
};

pub const Expr = union(ExprTag) {
pub const Expr = struct {
const Self = @This();

arith: ArithExpr,
bool_: BoolExpr,
fn_call: FnCallExpr,
str: []const u8,
cursor: Cursor,
file_path: []const u8,
file_content: []const u8,
as: ExprAs,

pub fn create_fn_call(name: []const u8, args: std.ArrayList(Expr)) Expr {
return .{ .fn_call = .{
.name = name,
.args = args,
} };
pub fn create_fn_call(
name: []const u8,
args: std.ArrayList(Expr),
file_path: []const u8,
cursor: Cursor,
file_content: []const u8,
) Expr {
return .{
.as = .{ .fn_call = .{
.name = name,
.args = args,
} },
.file_path = file_path,
.cursor = cursor,
.file_content = file_content,
};
}

pub fn create_str(content: []const u8) Expr {
return .{ .str = content };
pub fn create_str(
content: []const u8,
file_path: []const u8,
cursor: Cursor,
file_content: []const u8,
) Expr {
return .{
.as = .{ .str = content },
.file_path = file_path,
.cursor = cursor,
.file_content = file_content,
};
}

pub fn create_var(
name: []const u8,
file_path: []const u8,
cursor: Cursor,
file_content: []const u8,
) Expr {
return .{
.as = .{ .var_ = name },
.file_path = file_path,
.cursor = cursor,
.file_content = file_content,
};
}

pub fn print(self: Self) void {
switch (self) {
switch (self.as) {
.str => |str| std.debug.print("\"{s}\"", .{str}),
.fn_call => |fn_call| fn_call.print(),
else => panic("print unimplemented for {}", .{std.meta.activeTag(self)}),
.var_ => |var_| std.debug.print("{s}", .{var_}),
else => panic("print unimplemented for {}", .{std.meta.activeTag(self.as)}),
}
}
};

pub const ExprAs = union(ExprTag) {
const Self = @This();

arith: ArithExpr,
bool_: BoolExpr,
fn_call: FnCallExpr,
str: []const u8,
var_: []const u8,
};

const ArithExpr = struct {
value: i32,
};
Expand Down
52 changes: 52 additions & 0 deletions src/errors.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const std = @import("std");
const builtin = @import("builtin");

const lexer_pkg = @import("lexer.zig");

const Cursor = lexer_pkg.Cursor;

const panic = std.debug.panic;

pub fn print_error_line(
comptime fmt: []const u8,
args: anytype,
file_path: []const u8,
content: []const u8,
cursor: Cursor,
) void {
var begin: usize = cursor.pos;
var end: usize = cursor.pos;

var nb_line: usize = 3;
while (true) {
if (begin == 0) break;
if (content[begin] == '\n' and nb_line == 0) break;
if (content[begin] == '\n') nb_line -= 1;
begin -= 1;
}
while (begin > 0 and content[begin] != '\n') begin -= 1;

while (end < content.len and content[end] != '\n') end += 1;

const content_error = content[begin..end];

const GREEN_TAG = "\x1b[32m";
const RED_TAG = "\x1b[31m";
const END_TAG = "\x1b[0m";
std.debug.print(
"\n" ++ GREEN_TAG ++ "{s}:{}:{}" ++ END_TAG ++ " ",
.{
file_path,
cursor.row + 1,
cursor.col,
},
);

std.debug.print(fmt ++ "\n", args);
std.debug.print("{s}\n", .{content_error});

for (0..cursor.col - 1) |_| {
std.debug.print(" ", .{});
}
std.debug.print(RED_TAG ++ "^" ++ END_TAG ++ "\n", .{});
}
21 changes: 12 additions & 9 deletions src/lexer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub const Lexer = struct {
l.nexti();
}

fn current_line(l: *Lexer) []const u8 {
pub fn current_line(l: *Lexer) []const u8 {
var begin: usize = l.cursor.pos;
var end: usize = l.cursor.pos;

Expand All @@ -85,14 +85,17 @@ pub const Lexer = struct {
const END_TAG = "\x1b[0m";
if (l.token != expected) {
const panic_line = l.current_line();
std.debug.print("\n" ++ GREEN_TAG ++ "{s}:{}:{}" ++ END_TAG ++ " expected this `{s}`, found: `{s}` in line\n{s}\n", .{
l.file_path,
l.cursor.row + 1,
l.cursor.col,
expected.get_str(),
l.name.as_str(l.content),
panic_line,
});
std.debug.print(
"\n" ++ GREEN_TAG ++ "{s}:{}:{}" ++ END_TAG ++ " expected this `{s}`, found: `{s}` in line\n{s}\n",
.{
l.file_path,
l.cursor.row + 1,
l.cursor.col,
expected.get_str(),
l.name.as_str(l.content),
panic_line,
},
);

for (0..l.cursor.col - 1) |_| {
std.debug.print(" ", .{});
Expand Down
11 changes: 11 additions & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ const std = @import("std");

const lexer_pkg = @import("lexer.zig");
const parser_pkg = @import("parser.zig");
const sema_pkg = @import("sema.zig");

const Lexer = lexer_pkg.Lexer;
const SemaErr = sema_pkg.SemaErr;

const parse = parser_pkg.parse;
const sema = sema_pkg.sema;

const LIMIT = 1024 * 10;

Expand Down Expand Up @@ -33,6 +36,14 @@ pub fn main(init: std.process.Init) !void {
);

const ast = try parse(&l, alloc);
sema(alloc, &ast) catch |err| {
switch (err) {
SemaErr.UndeclaredVar => std.debug.print("Call to undeclared var", .{}),
SemaErr.CallUnknownFunction => std.debug.print("unknowns function", .{}),
SemaErr.OutOfMemory => return SemaErr.OutOfMemory,
}
return;
};

ast.print();

Expand Down
17 changes: 15 additions & 2 deletions src/parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ fn parse_expr(l: *Lexer, alloc: Allocator) error{OutOfMemory}!Expr {
// fn call
return parse_fn_call_expr(l, alloc);
}
const name = l.name.as_str(l.content);
l.eat(.id);
return Expr.create_var(
name,
l.file_path,
l.previous_cursor,
l.content,
);
} else if (l.token == .str) {
return parse_str(l);
}
Expand All @@ -173,7 +181,12 @@ fn parse_expr(l: *Lexer, alloc: Allocator) error{OutOfMemory}!Expr {
fn parse_str(l: *Lexer) !Expr {
const raw_str = l.name.as_str(l.content);
l.eat(.str);
return Expr.create_str(raw_str);
return Expr.create_str(
raw_str,
l.file_path,
l.previous_cursor,
l.content,
);
}

fn parse_fn_call_expr(l: *Lexer, alloc: Allocator) !Expr {
Expand All @@ -194,5 +207,5 @@ fn parse_fn_call_expr(l: *Lexer, alloc: Allocator) !Expr {
}
l.eat(.cparen);

return Expr.create_fn_call(fn_name, args);
return Expr.create_fn_call(fn_name, args, l.file_path, l.previous_cursor, l.content);
}
Loading
Loading