Something went wrong. Try again.
Embedded programming language for Zig
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152const std = @import("std");const Allocator = std.mem.Allocator;
const zexa = @import("./root.zig");const Value = zexa.lang.Value;const Scope = zexa.lang.Scope;const Number = zexa.lang.Number;const Environment = zexa.env.Environment;
const lexer = @import("./lexer.zig");const Tokenizer = lexer.Tokenizer;const Token = lexer.Token;const TokenValue = lexer.TokenValue;const LineInfo = lexer.LineInfo;
const util = @import("./util.zig");const SliceIterator = util.SliceIterator;const StringBuilder = util.StringBuilder;
pub const Parser = struct { const Self = @This();
allocator: Allocator, tokenizer: *Tokenizer, env: *Environment, ast: std.ArrayList(*Value), line: LineInfo = .{ .line = 0, .column = 0 },
pub const ParseError = error{ UnexpectedToken, UnexpectedEOF, UnclosedList, };
pub fn init(allocator: Allocator, tokenizer: *Tokenizer, env: *Environment) !Self { return .{ .allocator = allocator, .tokenizer = tokenizer, .env = env, .ast = try std.ArrayList(*Value).initCapacity(allocator, 1000), }; }
pub fn deinit(self: *Self) void { self.ast.deinit(self.allocator); }
pub fn parse(self: *Self) !void { var iter = SliceIterator(Token).init(self.tokenizer.tokens.items);
while (iter.next()) |tok| { try self.ast.append(self.allocator, try self.parseExpr(tok, &iter)); } }
pub fn parseExpr(self: *Self, token: Token, tokens: *SliceIterator(Token)) !*Value { const scope = &self.env.primary_scope;
self.line = token.line;
switch (token.value) { .num => |num| { const v = try std.fmt.parseFloat(Number, num); return try Value.initFromAny(scope, v); }, .sym => |sym| return try Value.initSymbol(scope, sym), .str => |str| return try Value.initString(scope, str), .quote => { const ntok = tokens.next() orelse return ParseError.UnexpectedEOF;
return try Value.initFromAny( scope, try self.parseExpr(ntok, tokens), ); }, .lparen => { const list = try Value.initCons( scope, try Value.initNil(scope), try Value.initNil(scope), );
var first = true;
if (tokens.peek()) |ptok| { switch (ptok.value) { .rparen => { _ = tokens.next(); return list; }, else => {}, } }
while (tokens.next()) |ntok| { switch (ntok.value) { .rparen => { break; }, else => { const val = try self.parseExpr(ntok, tokens); if (first) { list.expr.cons.car = val; first = false; } else { try list.append(scope, val); } }, } }
return list; }, .rparen => return ParseError.UnclosedList, } }};
test "parser" { var tokenizer = try Tokenizer.init(std.testing.allocator, @embedFile("./test/test1.zexa")); defer tokenizer.deinit();
try tokenizer.lex();
var env = try Environment.init(std.testing.allocator); defer env.deinit(); try zexa.corelib.loadCoreLibrary(&env.primary_scope);
var parser = try Parser.init(std.testing.allocator, &tokenizer, &env); try parser.parse(); defer parser.deinit();
_ = try env.primary_scope.evalAst(parser.ast.items);}
test "test" { var tokenizer = try Tokenizer.init(std.testing.allocator, "(lambda () (print hey))"); defer tokenizer.deinit(); try tokenizer.lex();
var env = try Environment.init(std.testing.allocator); defer env.deinit();
var parser = try Parser.init(std.testing.allocator, &tokenizer, &env); defer parser.deinit(); try parser.parse();
for (parser.ast.items) |v| { std.debug.print("value: {f}\n", .{v}); }}